package com.lancoo.cvas.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lancoo.cvas.arrangecourse.ArrangeCourseService;
import com.lancoo.cvas.entity.*;
import com.lancoo.cvas.exception.BizException;
import com.lancoo.cvas.mapper.*;
import com.lancoo.cvas.pojo.common.Deleted;
import com.lancoo.cvas.pojo.common.FixType;
import com.lancoo.cvas.pojo.common.PageInfo;
import com.lancoo.cvas.pojo.common.ScheduleState;
import com.lancoo.cvas.pojo.constant.GlobalConstant;
import com.lancoo.cvas.pojo.dto.FixDto;
import com.lancoo.cvas.pojo.dto.PeriodSchemeDto;
import com.lancoo.cvas.pojo.dto.ProhibitDto;
import com.lancoo.cvas.pojo.input.ClassInfoByClassInput;
import com.lancoo.cvas.pojo.input.ClassInfoByMajorInput;
import com.lancoo.cvas.pojo.vo.*;
import com.lancoo.cvas.service.*;
import com.lancoo.cvas.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service("basicRuleService")
public class BasicRuleServiceImpl implements BasicRuleService {

    @Resource
    private PlatformTransactionManager transactionManager;
    @Resource
    private TransactionDefinition def;

    @Resource
    private ClassInfoService classInfoService;
    @Resource
    private RuleWeekDayService ruleWeekDayService;

    @Resource
    private PeriodSchemeMapper periodSchemeMapper;
    @Resource
    private RoomService roomService;

    @Resource
    private RuleUsableMapper ruleUsableMapper;

    @Resource
    private RuleTeacherSettingService ruleTeacherSettingService;

    @Resource
    private CourseService courseService;

    @Resource
    private PlanTeachingCourseSegmentService planTeachingCourseSegmentService;

    @Resource
    private PlanTeachingCourseSegmentMapper planTeachingCourseSegmentMapper;

    @Resource
    private PlanTeachingService planTeachingService;

    @Resource
    private SegmentService segmentService;

    @Resource
    private RuleTimeProhibitService ruleTimeProhibitService;

    @Resource
    private RuleRoomProhibitService ruleRoomProhibitService;
    @Resource
    private RuleRoomProhibitMapper ruleRoomProhibitMapper;

    @Resource
    private MajorService majorService;

    @Resource
    private TaskToGradeService taskToGradeService;
    @Resource
    private RuleCourseProhibitService ruleCourseProhibitService;
    @Resource
    private RuleCourseProhibitMapper ruleCourseProhibitMapper;
    @Resource
    private RuleClassProhibitService ruleClassProhibitService;
    @Resource
    private RuleClassProhibitMapper ruleClassProhibitMapper;
    @Resource
    private RuleTeachingClassProhibitService ruleTeachingClassProhibitService;
    @Resource
    private RuleTeachingClassProhibitMapper ruleTeachingClassProhibitMapper;
    @Resource
    private RuleTeacherTimeService ruleTeacherTimeService;
    @Resource
    private RuleTeacherTimeMapper ruleTeacherTimeMapper;
    @Resource
    private TeacherService teacherService;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private TeachingClassTeacherService teachingClassTeacherService;

    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private RuleUsableService ruleUsableService;

    @Resource
    private StudentMapper studentMapper;

    @Resource
    private PlanTeachingStudentMapper planTeachingStudentMapper;

    @Resource
    private ClassCourseCloseService classCourseCloseService;
    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private RuleCourseService ruleCourseService;
    @Resource
    private RuleCourseProhibitMajorService ruleCourseProhibitMajorService;
    @Resource
    private ArrangeProcessService arrangeProcessService;
    @Resource
    private PlanTeachingMapper planTeachingMapper;
    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private SegmentMapper segmentMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private TeachingClassWeekMapper teachingClassWeekMapper;
    @Resource
    private TeachingClassTeacherMapper teachingClassTeacherMapper;
    @Resource
    private ScheduleConflictInfoService scheduleConflictInfoService;

    @Resource
    private ArrangeCourseService arrangeCourseService;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private TaskInfoMapper taskInfoMapper;
    @Resource
    private YunService yunService;


    @Override
    public CampusCrossGetResponse getClassInfo(Integer taskId, String gradeId, String keyword, String campusId, Integer currentPage, Integer pageSize) {


        //通过查询条件获取对应的行政班列表
        List<ClassInfo> ClassInfoList = classInfoService.lambdaQuery().eq(ClassInfo::getTaskId, taskId)
                .eq(StrUtil.isNotBlank(gradeId), ClassInfo::getGradeId, gradeId)
                .eq(StrUtil.isNotBlank(campusId), ClassInfo::getCampusId, campusId)
                .and(StrUtil.isNotBlank(keyword), wrapper -> wrapper.like(ClassInfo::getClassName, keyword))
                .list().stream()
                .sorted(Comparator.comparing(ClassInfo::getGradeName))
                .sorted(Comparator.comparing(ClassInfo::getClassName))
                .collect(Collectors.toList());


        //分页
        PageInfo<ClassInfo> classPage = PagingUtil.getPages(currentPage, pageSize, ClassInfoList);

        long ClassNum = ClassInfoList.stream().map(ClassInfo::getClassId).distinct().count();

        return CampusCrossGetResponse.builder()
                .facultyClassInfoList(classPage.getList())
                .totalClass(ClassNum)
                .currentPage(classPage.getCurrentPage())
                .pageSize(classPage.getPageSize())
                .total(classPage.getTotal())
                .build();
    }

    /**
     * @param taskId:
     * @param weekSet:       大小周设置
     * @param schoolId:
     * @param term:
     * @param periodSchemes: 课时方案列表
     * @Description: 初始化课时方案设置
     * @Author: liufeng
     * @Date: 2023/12/4 20:02
     * @return:
     */
    @Override
    public void initWeekDays(Integer taskId, Integer weekSet, String schoolId, String term, List<PeriodScheme> periodSchemes) {
        //先判断是否已经设置过了
        boolean exists = ruleWeekDayService.lambdaQuery().eq(RuleWeekDay::getSchoolId, schoolId)
                .eq(RuleWeekDay::getTerm, term)
                .exists();
        if (exists) {
            return;
        }
        if (CollUtil.isNotEmpty(periodSchemes)) {
            List<RuleWeekDay> weekDays = new ArrayList<>();
            PeriodScheme periodScheme = periodSchemes.stream().findFirst().get();
            for (int i = 1; i <= 5; i++) {
                RuleWeekDay ruleWeekDay = new RuleWeekDay();
                weekDays.add(ruleWeekDay.setTaskId(taskId)
                        .setBaseSchemeId(periodScheme.getBaseSchemeId())
                        .setBaseSchemeName(periodScheme.getBaseSchemeName())
                        .setSchoolId(schoolId)
                        .setTerm(term)
                        .setWeekDayCode(String.format("%02d", i)));
            }
            if (weekSet.equals(1)) {
                for (int i = 8; i <= 12; i++) {
                    RuleWeekDay ruleWeekDay = new RuleWeekDay();
                    weekDays.add(ruleWeekDay.setTaskId(taskId)
                            .setBaseSchemeId(periodScheme.getBaseSchemeId())
                            .setBaseSchemeName(periodScheme.getBaseSchemeName())
                            .setSchoolId(schoolId)
                            .setTerm(term)
                            .setWeekDayCode(String.format("%02d", i)));
                }
            }
//            //设置课时规则校区
//            List<Campus> campusList = roomService.getCampusList(taskId);
//            if (CollUtil.isNotEmpty(campusList)) {
//                weekDays = weekDays.stream().map(weekDay -> weekDay.setCampusId(campusList.get(0).getCampusId()))
//                        .collect(Collectors.toList());
//                for (int i = 1; i < campusList.size(); i++) {
//                    List<RuleWeekDay> campusWeekDays = new ArrayList<>(weekDays);
//                    String campusId = campusList.get(i).getCampusId();
//                    weekDays.addAll(campusWeekDays.stream().map(weekDay -> weekDay.setCampusId(campusId))
//                            .collect(Collectors.toList()));
//                }
//            }

            ruleWeekDayService.saveBatch(weekDays);
        }
    }

    /**
     * @param schoolId:
     * @param term:
     * @Description: 根据学校id 学期id获取课时方案设置
     * @Author: liufeng
     * @Date: 2023/12/4 20:15
     * @return:
     */
    @Override
    public List<PeriodSchemeGroupVo> getPeriodSchemes(Integer taskId, String schoolId, String term) {
        List<PeriodSchemeGroupVo> schemeList = new ArrayList<>();
        //根据学校学期获取所有课时方案
        List<PeriodScheme> periodSchemes = periodSchemeMapper.selectList(new LambdaQueryWrapper<PeriodScheme>()
                .eq(PeriodScheme::getSchoolId, schoolId)
                .eq(PeriodScheme::getTerm, term)
                .eq(PeriodScheme::getDeleted, Deleted.NOT.getCode()));
        //根据课时方案id分组
        Map<String, List<PeriodScheme>> periodMap = periodSchemes.stream().collect(Collectors.groupingBy(PeriodScheme::getBaseSchemeId));
        //构造课时方案返回体
        periodMap.forEach((key, value) -> {
            schemeList.add(PeriodSchemeGroupVo.builder()
                    .baseSchemeId(key)
                    .baseSchemeName(value.get(0).getBaseSchemeName())
                    .periodSchemes(value).build());
        });
        return schemeList;
    }


    /**
     * @param schoolId:
     * @param term:
     * @Description: 根据学校id 学期id获取课时方案设置
     * @Author: liufeng
     * @Date: 2023/12/4 20:27
     * @return:
     */
    @Override
    public List<RuleWeekDay> getWeekDays(Integer taskId, String schoolId, String term) {
        //根据学校学期获取每天使用的课时方案
        List<RuleWeekDay> weekDays = ruleWeekDayService.lambdaQuery()
                .eq(RuleWeekDay::getSchoolId, schoolId)
                .eq(RuleWeekDay::getTerm, term)
                .eq(RuleWeekDay::getDeleted, Deleted.NOT.getCode()).list();
        //获取课时方案信息
        List<PeriodScheme> periodSchemes = periodSchemeMapper.selectList(new LambdaQueryWrapper<PeriodScheme>()
                .eq(PeriodScheme::getSchoolId, schoolId)
                .eq(PeriodScheme::getTerm, term)
                .eq(PeriodScheme::getDeleted, Deleted.NOT.getCode()));
        //分组
        Map<String, List<PeriodScheme>> periodMap = periodSchemes.stream().collect(Collectors.groupingBy(PeriodScheme::getBaseSchemeId));
        //填充节次信息
        weekDays.forEach(day -> {
            day.setPeriodSchemes(periodMap.get(day.getBaseSchemeId()));
        });
        return weekDays;
    }


    /**
     * @param taskId:
     * @param weekDays:
     * @Description : 更新课时方案设置，暂时同一个学校同一个学期只有第一个任务时可以设置
     * @Author: liufeng
     * @Date: 2023/12/5 9:40
     * @return:
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateWeekDay(Integer taskId, List<RuleWeekDay> weekDays) {
//        //检查是否设置了课时禁排  设置就不允许修改
//        List<RuleTimeProhibit> list = ruleTimeProhibitService.lambdaQuery().eq(RuleTimeProhibit::getTaskId, taskId)
//                .eq(RuleTimeProhibit::getDeleted, Deleted.NOT.getCode()).list();
//        if (CollUtil.isNotEmpty(list)) {
//            throw new BizException(5, "已经设置了课时禁排，请先取消课时禁排");
//        }


        if (weekDays.size() > 0) {
            //获取timeCode

            String schoolId = weekDays.get(0).getSchoolId();
            String term = weekDays.get(0).getTerm();
            //检查其他任务是否排课了  设置就不允许修改
            Integer count = scheduleMapper.checkHasSchedule(taskId, schoolId, term, Deleted.NOT.getCode());
            if (count != null && count > 0) {
                throw new BizException(5, "同学期的其他计划已经进行了排课，课时方案暂不支持修改");
            }
//            if (count != null && count == 1) {
//                //删除课表  冲突  排课状态
//            }


            List<String> oldTimeCode = new ArrayList<>();
            List<String> nowTimeCode = new ArrayList<>();


            Map<String, List<PeriodScheme>> schemeMap = periodSchemeMapper.getTermPeriodScheme(schoolId, term)
                    .stream().collect(Collectors.groupingBy(PeriodScheme::getBaseSchemeId));

            //原来的课时
            List<RuleWeekDay> oldWeekDays = ruleWeekDayService.lambdaQuery()
                    .eq(RuleWeekDay::getSchoolId, schoolId)
                    .eq(RuleWeekDay::getTerm, term)
                    .eq(RuleWeekDay::getDeleted, Deleted.NOT.getCode()).list();
            //收集原来的课时
            for (RuleWeekDay weekDay : oldWeekDays) {
                String weekDayCode = weekDay.getWeekDayCode();
                List<PeriodScheme> schemeList = schemeMap.get(weekDay.getBaseSchemeId());
                schemeList.forEach(o -> oldTimeCode.add(weekDayCode + "0" + o.getPeriod()));
            }


            //收集现在的课时
            for (RuleWeekDay weekDay : weekDays) {
                String weekDayCode = weekDay.getWeekDayCode();
                List<PeriodScheme> schemeList = schemeMap.get(weekDay.getBaseSchemeId());
                schemeList.forEach(o -> nowTimeCode.add(weekDayCode + "0" + o.getPeriod()));
            }
            //计算少掉的课时
            List<String> removeTimeCodes = CollUtil.subtractToList(oldTimeCode, nowTimeCode);
            //如果少掉一些课时  删除该课时的规则和课表信息
            if (CollUtil.isNotEmpty(removeTimeCodes)) {
                List<Long> unSuitIds = ruleTeachingClassProhibitService.lambdaQuery()
                        .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                        .eq(RuleTeachingClassProhibit::getFlag, 1)
                        .in(RuleTeachingClassProhibit::getTimeCode, removeTimeCodes)
                        .list().stream().map(RuleTeachingClassProhibit::getTeachingClassId)
                        .distinct().collect(Collectors.toList());

                //删除固排 禁排信息
                timeProhibitSuit(taskId, removeTimeCodes, -1);

                //删除课表  冲突  更新排课状态
//                removeAllSchedules(taskId);
                removeSchedules(taskId, removeTimeCodes);
                //如果是未满足规则的
                if (CollUtil.isNotEmpty(unSuitIds)) {
                    //跟新排课状态
                    unSuitIds.forEach(o -> arrangeCourseService.manualAdjustmentUpdate(schoolId, term, taskId, null, o));
                }
            }


            //更新当前课时方案
            ruleWeekDayService.lambdaUpdate().eq(RuleWeekDay::getTaskId, taskId).remove();
            ruleWeekDayService.saveBatch(weekDays);
        }
        return true;
    }

    private void removeAllSchedules(Integer taskId) {
        scheduleMapper.reAutoArrange(taskId);
    }


    private void removeSchedules(Integer taskId, List<String> removeTimeCodes) {
        List<Schedule> schedules = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .eq(Schedule::getTaskId, taskId)
                .in(Schedule::getTimeCode, removeTimeCodes)
                .eq(Schedule::getDeleted, Deleted.NOT.getCode()));
        if (CollUtil.isEmpty(schedules)) {
            return;
        }

//        //删除课表
//        scheduleMapper.delete(new LambdaQueryWrapper<Schedule>()
//                .in(Schedule::getTimeGroup,
//                        schedules.stream()
//                                .map(Schedule::getTimeGroup)
//                                .distinct().collect(Collectors.toList()))
//        );

        //删除课表
        scheduleMapper.deleteScheduleByClassAndType(schedules);

        //删除冲突信息
        List<ScheduleConflictInfo> conflictInfoList = scheduleConflictInfoService.lambdaQuery()
                .eq(ScheduleConflictInfo::getTaskId, taskId)
                .in(ScheduleConflictInfo::getTimeCode, removeTimeCodes)
                .eq(ScheduleConflictInfo::getDeleted, Deleted.NOT.getCode())
                .list();

        if (CollUtil.isNotEmpty(conflictInfoList)) {
            List<String> timeGroup = conflictInfoList.stream().map(ScheduleConflictInfo::getTimeGroup).distinct().collect(Collectors.toList());
            List<String> clashTimeGroup = conflictInfoList.stream().map(ScheduleConflictInfo::getClashTimeGroup).distinct().collect(Collectors.toList());

            scheduleConflictInfoService.lambdaUpdate()
                    .in(ScheduleConflictInfo::getTimeGroup, timeGroup)
                    .or()
                    .in(ScheduleConflictInfo::getClashTimeGroup, clashTimeGroup)
                    .remove();
        }


        //更新排课状态 和 锁定状态
        teachingClassWeekMapper.updateScheduleStateAndIsLocked(ScheduleState.UNARRANGE.getCode(), schedules);
        teachingClassWeekMapper.setUnLock(taskId);
        arrangeProcessService.lambdaUpdate().eq(ArrangeProcess::getTaskId,taskId)
                .set(ArrangeProcess::getIsLocked,1).update();

    }


    @Override
    public void initRuleUsable(Integer taskId, String schoolId, String term) {
        List<RuleUsable> usableList = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            RuleUsable ruleUsable = new RuleUsable();
            usableList.add(ruleUsable.setTaskId(taskId)
                    .setSchoolId(schoolId)
                    .setTerm(term)
                    .setCode(i)
                    .setOption("a"));
        }
        for (int i = 6; i <= 20; i++) {
            if (i == 13) {
                continue;
            }
            RuleUsable ruleUsable = new RuleUsable();
            usableList.add(ruleUsable.setTaskId(taskId)
                    .setSchoolId(schoolId)
                    .setTerm(term)
                    .setCode(i)
                    .setOption("b"));
        }
        ruleUsableMapper.addBatch(usableList);
        //学校学期共享数据 课时方案统一设置
        Long count = ruleUsableMapper.selectCount(new LambdaQueryWrapper<RuleUsable>()
                .eq(RuleUsable::getSchoolId, schoolId).eq(RuleUsable::getTerm, term).eq(RuleUsable::getCode, 13));
        if (count == 0) {
            ruleUsableMapper.addBatch(Collections.singletonList(new RuleUsable().setTaskId(taskId)
                    .setSchoolId(schoolId)
                    .setTerm(term)
                    .setCode(13)
                    .setOption("a")));
        }

        //初始化教师统一设置
        ruleTeacherSettingService.save(new RuleTeacherSetting().setTaskId(taskId).setMaxSection(4));
    }


    @Override
    public boolean setCampus(List<Long> classIds, String campusId, String campusName) {
        //设置校区
        boolean update = classInfoService.lambdaUpdate().set(ClassInfo::getCampusId, campusId)
                .set(ClassInfo::getCampusName, campusName)
                .in(CollUtil.isNotEmpty(classIds), ClassInfo::getId, classIds).set(ClassInfo::getRoomId,null)
                .update();


        return update;
    }

    @Override
    public MaxPeriodScheme getMaxPeriodScheme(Integer taskId, String schoolId, String term) {
        List<RuleWeekDay> weekDays = this.getWeekDays(taskId, schoolId, term);
        if (weekDays.size() == 0) {
            return null;
        }
//        判断是统一设置还是单日设置
        boolean flag = weekDays.stream()
                .map(RuleWeekDay::getBaseSchemeId)
                .allMatch(value -> value.equals(weekDays.get(0).getBaseSchemeId()));

        List<PeriodScheme> periodSchemes;
        //获取最大的课时
        periodSchemes = weekDays.stream().max(Comparator.comparing(g -> g.getPeriodSchemes().size())).get().getPeriodSchemes();
        return MaxPeriodScheme.builder().isUniformly(flag).periodSchemes(periodSchemes).build();
    }

    /**
     * @param schoolId:
     * @param term:
     * @Description: 根据学校id 学期id获取日期禁排
     * @Author: liufeng
     * @Date: 2023/12/5 15:01
     * @return:
     */
    @Override
    public List<RuleTimeProhibit> getTimeProhibit(Integer taskId, String schoolId, String term) {
        List<RuleTimeProhibit> timeProhibits = ruleTimeProhibitService.lambdaQuery()
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .eq(RuleTimeProhibit::getSchoolId, schoolId).eq(RuleTimeProhibit::getTerm, term)
                .eq(RuleTimeProhibit::getDeleted, Deleted.NOT.getCode()).list();
        return timeProhibits;
    }

    /**
     * @param taskId:
     * @param ruleTimeProhibit:
     * @Description: 设置日期禁排 相当于禁排所有周次的某一节课
     * @Author: liufeng
     * @Date: 2023/12/5 19:21
     * @return:
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer setTimeProhibit(Integer taskId, RuleTimeProhibit ruleTimeProhibit) {
        if (ruleTimeProhibit.getDeleted() == Deleted.YES.getCode()) {
            //取消禁排
            ruleTimeProhibitService.updateById(ruleTimeProhibit);
            return -1;
        } else {
            //设置禁排
            //检查固排 以下面的方法二选一
//            setTimeProhibitCheck(taskId, ruleTimeProhibit.getTimeCode());

            //删除冲突课时固排禁排
            timeProhibitSuit(taskId, Collections.singletonList(ruleTimeProhibit.getTimeCode()), 0);

            ruleTimeProhibitService.saveOrUpdate(ruleTimeProhibit);
            return ruleTimeProhibit.getId();
        }
    }

    /**
     * @param taskId:
     * @Description: 清空课时禁排
     * @Author: liufeng
     * @Date: 2023/12/14 18:57
     * @return:
     */
    @Override
    public Boolean clearTimeProhibit(Integer taskId) {
        ruleTimeProhibitService.lambdaUpdate()
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .set(RuleTimeProhibit::getDeleted, Deleted.YES.getCode()).update();
        return true;
    }

    /**
     * @param taskId:
     * @Description: 检测是否设置下面的流程
     * @Author: liufeng
     * @Date: 2023/12/8 11:13
     * @return:
     */
    private void setTimeProhibitCheck(Integer taskId, String timeCode) {
        //检测是否设置下面的流程
        Long count;
//        count = ruleRoomProhibitService.lambdaQuery().eq(RuleRoomProhibit::getTaskId, taskId)
//                .eq(RuleRoomProhibit::getDeleted, Deleted.NOT.getCode()).count();
//        if (count > 0) {
//            throw new BizException(5, "已经设置了固排禁排规则，设置课时禁排失败");
//        }
//        count = ruleTeacherTimeService.lambdaQuery().eq(RuleTeacherTime::getTaskId, taskId)
//                .eq(RuleTeacherTime::getDeleted, Deleted.NOT.getCode()).count();
//        if (count > 0) {
//            throw new BizException(5, "已经设置了固排禁排规则，设置课时禁排失败");
//        }
//        count = ruleCourseProhibitService.lambdaQuery().eq(RuleCourseProhibit::getTaskId, taskId)
//                .eq(RuleCourseProhibit::getDeleted, Deleted.NOT.getCode()).count();
//        if (count > 0) {
//            throw new BizException(5, "已经设置了固排禁排规则，设置课时禁排失败");
//        }
//        count = ruleClassProhibitService.lambdaQuery().eq(RuleClassProhibit::getTaskId, taskId)
//                .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode()).count();
//        if (count > 0) {
//            throw new BizException(5, "已经设置了固排禁排规则，设置课时禁排失败");
//        }

        //检查教学班是否在此课时固排
        count = ruleTeachingClassProhibitService.lambdaQuery().eq(RuleTeachingClassProhibit::getTaskId, taskId)
                .eq(RuleTeachingClassProhibit::getFlag, 1)
                .eq(RuleTeachingClassProhibit::getTimeCode, timeCode)
                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode()).count();
        if (count > 0) {
            throw new BizException(5, "教学班在课时：" + TimeCodeUtil.convert(timeCode) +
                    "已经设置了固排规则，设置课时禁排失败");
        }
    }

    /**
     * @param setBasciRuleRequest:
     * @param setBasciRuleRequest:
     * @param setBasciRuleRequest:
     * @Description: 设置基础规则
     * @Author: liufeng
     * @Date: 2023/12/5 19:27
     * @return:
     */
    @Override
    public void setBasicRule(SetBasciRuleRequest setBasciRuleRequest) {
        ruleUsableMapper.setBasicRule(setBasciRuleRequest.getRules(), setBasciRuleRequest.getTaskId());
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param term:
     * @Description: 获取基础规则
     * @Author: liufeng
     * @Date: 2023/12/5 19:37
     * @Description: 获取基础规则
     * @Author: liufeng
     * @Date: 2023/12/5 19:37
     * @Description: 获取基础规则
     * @Author: liufeng
     * @Date: 2023/12/5 19:37
     * @return:
     */
    @Override
    public List<RuleUsable> getCurrent(Integer taskId, String schoolId, String term) {
        if (StrUtil.isNotBlank(schoolId)) {
            return ruleUsableMapper.getBySchoolTerm(schoolId, term);
        }
        return ruleUsableMapper.getByTaskId(taskId);
    }

    @Override
    public ClassInfoByClassResponses getClassInfoByClass(Integer taskId, String gradeId, String keyword, Integer currentPage, Integer pageSize) {


        //通过条件进行筛选对应行政班信息
        List<ClassInfo> ClassInfoList = classInfoService.lambdaQuery().eq(ClassInfo::getTaskId, taskId)
                .eq(StrUtil.isNotBlank(gradeId), ClassInfo::getGradeId, gradeId)
                .and(StrUtil.isNotBlank(keyword), wrapper -> wrapper.like(ClassInfo::getClassName, keyword))
                .list();


        List<ClassInfoVo> classInfoVos = new ArrayList<>();

        //获取课程
        List<Course> courses = courseMapper.getCourseList(taskId);


        //获取环节
        List<Segment> segments = segmentMapper.getSegmentList(taskId);

        TaskInfo taskInfo = taskInfoService.getById(taskId);


        //获取教室
        List<Room> roomList = roomMapper.selectRoomList(taskInfo.getSchoolId(), taskInfo.getTerm());


        //获取培养方案对应学生
        List<PlanTeachingToStudent> planTeachingToStudentList = planTeachingStudentMapper.selectPlanTeachingToStudentList(taskId, Deleted.NOT.getCode());

        //获取培养方案对应课程
        List<PlanTeachingCourseSegment> planTeachingCourseSegments = planTeachingCourseSegmentMapper.selectPlanTeachingCourseSegmentList(taskId, Deleted.NOT.getCode());

        //获取对应培养方案
        List<PlanTeaching> planTeachings = planTeachingMapper.selectPlanTeachingList(taskId, Deleted.NOT.getCode());


        //通过班级的年级和专业id，筛选对应的教学计划，然后根据PlanTeachingCourseSegment找到教学计划对应的环节
        if (CollUtil.isNotEmpty(ClassInfoList)) {
            for (ClassInfo classInfo : ClassInfoList) {

                List<PlanTeachingToStudent> planTeachingToStudents = planTeachingToStudentList.stream()
                        .filter(p -> p.getClassId().equals(classInfo.getClassId())).collect(Collectors.toList());


                List<PlanTeaching> pTeaching = planTeachings.stream()
                        .filter(p -> planTeachingToStudents.stream().anyMatch(o -> p.getBaseTeachingPlanId().equals(o.getBaseTeachingPlanId())))
                        .collect(Collectors.toList());

                if (CollUtil.isEmpty(pTeaching)) {
                    continue;
                }

                //通过培养方案获取对应课程
                Set<String> baseCourse = new HashSet<>();
                if (CollUtil.isNotEmpty(pTeaching)) {
                    for (PlanTeaching planTeaching : pTeaching) {

                        List<PlanTeachingCourseSegment> pTeachingCourseSegments = planTeachingCourseSegments.stream()
                                .filter(p -> p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId())
                                        && planTeaching.getDeleted() == 0 && p.getDeleted() == Deleted.NOT.getCode() && p.getFlag() == 1).collect(Collectors.toList());


                        if (CollUtil.isNotEmpty(pTeachingCourseSegments)) {
                            for (PlanTeachingCourseSegment pTeachingCourseSegment : pTeachingCourseSegments) {

                                if (!baseCourse.contains(pTeachingCourseSegment.getBaseCourseId())) {
                                    baseCourse.add(pTeachingCourseSegment.getBaseCourseId());
                                }

                            }
                        }
                    }
                }


                //判断课程是否被启用
                List<Course> courseList = new ArrayList<>();
                if (CollUtil.isNotEmpty(baseCourse)) {
                    for (String c : baseCourse) {
                        List<Course> coursesCount = courses.stream()
                                .filter(p -> p.getBaseCourseId().equals(c))
                                .collect(Collectors.toList());
                        courseList.addAll(coursesCount);
                    }
                }

                //获取未启用课程，进行过滤
                List<ClassCourseClose> classCourseCloses = classCourseCloseService.lambdaQuery()
                        .eq(ClassCourseClose::getTaskId, taskId).eq(ClassCourseClose::getClassId, classInfo.getClassId()).eq(ClassCourseClose::getFlag, 1)
                        .eq(ClassCourseClose::getDeleted, Deleted.YES.getCode()).list();

                List<Long> courseIds = classCourseCloses.stream().map(ClassCourseClose::getCourseId).distinct().collect(Collectors.toList());

                List<Course> courseUnEnable = courseList.stream().filter(p -> courseIds.stream().anyMatch(o -> p.getCourseId().equals(o))).collect(Collectors.toList());

                courseList.removeAll(courseUnEnable);



                //获取环节对应培养计划
                Set<String> baseSegment = new HashSet<>();
                if (CollUtil.isNotEmpty(pTeaching)) {
                    for (PlanTeaching planTeaching : pTeaching) {

                        List<PlanTeachingCourseSegment> pTeachingCourseSegments = planTeachingCourseSegments.stream()
                                .filter(p -> p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId())
                                        && p.getFlag() == 2).collect(Collectors.toList());

                        if (CollUtil.isNotEmpty(pTeachingCourseSegments)) {
                            for (PlanTeachingCourseSegment pTeachingCourseSegment : pTeachingCourseSegments) {
                                if (!baseSegment.contains(pTeachingCourseSegment.getBaseCourseId())) {
                                    baseSegment.add(pTeachingCourseSegment.getBaseCourseId());
                                }
                            }
                        }
                    }
                }

                //判断环节是否被禁用
                List<Segment> segmentList = new ArrayList<>();
                if (CollUtil.isNotEmpty(baseSegment)) {
                    for (String c : baseSegment) {
                        List<Segment> segmentCount = segments.stream()
                                .filter(p -> p.getBaseSegmentId().equals(c))
                                .collect(Collectors.toList());
                        segmentList.addAll(segmentCount);
                    }
                }


                //获取未启用环节进行过滤
                List<ClassCourseClose> classSegmentCloses = classCourseCloseService.lambdaQuery()
                        .eq(ClassCourseClose::getTaskId, taskId).eq(ClassCourseClose::getClassId, classInfo.getClassId()).eq(ClassCourseClose::getFlag, 2)
                        .eq(ClassCourseClose::getDeleted, Deleted.YES.getCode()).list();

                List<Long> segmentIds = classSegmentCloses.stream().map(ClassCourseClose::getCourseId).distinct().collect(Collectors.toList());

                List<Segment> segmentUnEnable = segmentList.stream().filter(p -> segmentIds.stream().anyMatch(o -> p.getSegmentId().equals(o))).collect(Collectors.toList());

                segmentList.removeAll(segmentUnEnable);


                List<Room> rooms = new ArrayList<>();
                if (classInfo.getRoomId() != null) {
                    rooms = roomList.stream().filter(p -> p.getRoomId().equals(classInfo.getRoomId())).collect(Collectors.toList());
                }


                ClassInfoVo classInfoVo = new ClassInfoVo();
                classInfoVo.setClassName(classInfo.getClassName())
                        .setClassId(classInfo.getClassId())
                        .setGradeId(classInfo.getGradeName())
                        .setGradeName(classInfo.getGradeName())
                        .setMajorId(classInfo.getMajorId())
                        .setMajorName(classInfo.getMajorName())
                        .setGenderId(classInfo.getGenderId())
                        .setGenderName(classInfo.getGenderName())
                        .setCourseNum(courseList.size())
                        .setSegmentNum(segmentList.size())
                        .setCampusId(classInfo.getCampusId())
                        .setCampusName(classInfo.getCampusName());

                if (CollUtil.isNotEmpty(rooms)) {
                    Room room = rooms.get(0);
                    classInfoVo.setRoomId(room.getRoomId());
                    classInfoVo.setRoomName(room.getRoomName());
                }
                classInfoVos.add(classInfoVo);
            }

        }


        //返回对应行政班对应信息
        PageInfo<ClassInfoVo> classPage = PagingUtil.getPages(currentPage, pageSize, classInfoVos);

        List<ClassInfoVo> collect = classPage.getList().stream().sorted((s1, s2) -> {
            int gradeComparison = s1.getGradeName().compareTo(s2.getGradeName());
            if (gradeComparison != 0) {
                return gradeComparison;
            } else {
                return s1.getClassName().compareTo(s2.getClassName());
            }
        }).collect(Collectors.toList());


        long ClassNum = classInfoVos.size();


        return ClassInfoByClassResponses.builder()
                .facultyClassInfoList(collect)
                .totalClass(ClassNum)
                .currentPage(classPage.getCurrentPage())
                .pageSize(classPage.getPageSize())
                .total(classPage.getTotal())
                .build();
    }

    /**
     * @param importProhibit:
     * @param file:
     * @Description: 导入禁排
     * @Author: liufeng
     * @Date: 2023/12/5 20:24
     * @return:
     */
    @Override
    public Result excelToProhibit(HttpServletResponse response, ImportProhibit importProhibit, MultipartFile file) {

        Result res = new Result();
        try {
            InputStream inputStream = file.getInputStream();
            ExcelReader reader = ExcelUtil.getReader(inputStream);
            List<Map<String, Object>> read = reader.read(2, 3, reader.getRowCount());
            if (CollUtil.isEmpty(read)) {
                throw new BizException(5, "导入文件数据为空");
            }
            if (importProhibit.getMark() == 1) {
                res = toTimeProhibit(importProhibit, read);
            }
            if (importProhibit.getMark() == 2) {
                res = toRoomProhibit(response, importProhibit, read);
            }
            if (importProhibit.getMark() == 3) {
                res = toTeacherProhibit(response, importProhibit, read);
            }
//            if (importProhibit.getMark() == 4) {
//                toCourseProhibit(importProhibit, read);
//            }
            if (importProhibit.getMark() == 5) {
                res = toClassProhibit(response, importProhibit, read);
            }
            if (importProhibit.getMark() == 6) {
                res = toTeachingClassProhibit(response, importProhibit, read);
            }
            reader.close();
        } catch (IOException e) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }
        return res;
    }

    @Deprecated
    private void toCourseProhibit(ImportProhibit importProhibit, List<Map<String, Object>> read) {
        Map<String, Long> courseMap = new HashMap<>();
        List<String> titleList = Arrays.asList("课程名称", "禁排/固排", "时间", "年级", "专业");
        List<RuleClassProhibit> ruleClassProhibits = new ArrayList<>();
        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取全部课程
        List<String> courseNames = read.stream()
                .map(o -> o.get("课程名称").toString())
                .distinct().collect(Collectors.toList());
        //获取全部课程信息
        if (CollUtil.isNotEmpty(courseNames)) {
            courseMap = courseService.lambdaQuery()
                    .eq(Course::getTaskId, importProhibit.getTaskId())
                    .eq(Course::getDeleted, Deleted.NOT.getCode())
                    .in(Course::getCourseName, courseNames).list()
                    .stream().collect(Collectors.toMap(Course::getCourseName, Course::getCourseId));
        }

        //获取全部年级专业
        List<String> gradeNames = read.stream()
                .map(o -> o.get("年级").toString())
                .distinct().collect(Collectors.toList());
        //获取全部年级专业
        List<String> majorNames = read.stream()
                .map(o -> o.get("专业").toString())
                .distinct().collect(Collectors.toList());

        //获取班级全部年级专业
        List<ClassInfo> classList = new ArrayList<>();
        Map<String, String> grades = new HashMap<>();
        Map<String, Long> majors = new HashMap<>();
        if (CollUtil.isNotEmpty(gradeNames)) {
            classList = classInfoService.lambdaQuery()
                    .eq(ClassInfo::getTaskId, importProhibit.getTaskId())
                    .eq(ClassInfo::getSchoolId, importProhibit.getSchoolId())
                    .in(ClassInfo::getGradeName, gradeNames)
                    .list();
            grades = classList.stream()
                    .collect(Collectors.toMap(ClassInfo::getGenderName, ClassInfo::getGenderId));
//            majors = classList.stream()
//                    .collect(Collectors.toMap(ClassInfo::getMajorName, ClassInfo::getMajorId));
        }

        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        //遍历
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> courseProhibit = read.get(i);
            String courseName = courseProhibit.get("课程名称").toString();
            String gradeName = courseProhibit.get("年级").toString();
            String majorName = courseProhibit.get("专业").toString();
            String rule = courseProhibit.get("禁排/固排").toString();
            String timeCodeProhibit = courseProhibit.get("时间").toString();

            if (!courseMap.containsKey(courseName)) {
                throw new BizException(5, ("第" + (i + 4) + "课程不存在" + courseName));
            }
            if (!courseMap.containsKey(gradeName)) {
                throw new BizException(5, ("第" + (i + 4) + "年级不存在" + courseName));
            }
            if (!courseMap.containsKey(majorName)) {
                throw new BizException(5, ("第" + (i + 4) + "专业不存在" + courseName));
            }

            if (StrUtil.isNotBlank(timeCodeProhibit)) {
                String[] split = timeCodeProhibit.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        throw new BizException(5, ("第" + (i + 4) + "排时间" + timeCode + "超出课时方案"));
                    }
                }
            }


        }
        List<RuleClassProhibit> addList = new ArrayList<>();
        if (importProhibit.getIsCoverage()) {
            ruleClassProhibitService.lambdaUpdate().eq(RuleClassProhibit::getClassId, importProhibit.getTaskId())
                    .set(RuleClassProhibit::getDeleted, Deleted.YES.getCode()).update();
            addList = ruleClassProhibits.stream().distinct().collect(Collectors.toList());
        } else {
            //获取已存在禁排
            List<RuleClassProhibit> existProhibit = ruleClassProhibitService.lambdaQuery()
                    .eq(RuleClassProhibit::getTaskId, importProhibit.getTaskId())
                    .eq(RuleClassProhibit::getFlag, 2)
                    .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode()).list();

            for (RuleClassProhibit ruleClassProhibit : existProhibit) {
                Optional<RuleClassProhibit> isCoverage = existProhibit.stream()
                        .filter(o -> o.getTimeCode().equals(ruleClassProhibit.getTimeCode())
                                && o.getClassId().equals(ruleClassProhibit.getClassId())).findFirst();
                if (!isCoverage.isPresent()) {
                    addList.add(ruleClassProhibit);
                }
            }
        }

        if (CollUtil.isNotEmpty(addList)) {
            ruleClassProhibitService.saveBatch(addList);
        }
    }

    /**
     * @param schoolId:
     * @param term:
     * @param roomId:
     * @Description: 根据id获取教室禁排时间
     * @Author: liufeng
     * @Date: 2023/12/6 15:44
     * @return:
     */
    @Override
    public List<RuleRoomProhibit> getRoomProhibit(Integer taskId, String schoolId, String term, Long roomId) {
        List<RuleRoomProhibit> roomProhibits = ruleRoomProhibitService.lambdaQuery()
                .eq(RuleRoomProhibit::getTaskId, taskId)
                .eq(RuleRoomProhibit::getSchoolId, schoolId)
                .eq(RuleRoomProhibit::getTerm, term)
                .eq(RuleRoomProhibit::getRoomId, roomId)
                .eq(RuleRoomProhibit::getDeleted, Deleted.NOT.getCode()).list();
        return roomProhibits;
    }

    /**
     * @param taskId:
     * @param ruleRoomProhibit:
     * @Description: 设置教室禁排
     * @Author: liufeng
     * @Date: 2023/12/7 19:31
     * @return:
     */
    @Override
    public boolean setRoomProhibit(Integer taskId, RuleRoomProhibit ruleRoomProhibit) {
        if (ruleRoomProhibit.getDeleted() == Deleted.NOT.getCode()) {
            List<Long> ids = teachingClassService.getTeachingClassIdsByRoomId(taskId, ruleRoomProhibit.getRoomId())
                    .stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
//            List<Long> ids = teachingClassWeekService.lambdaQuery()
//                    .eq(TeachingClassWeek::getRoomId, ruleRoomProhibit.getRoomId())
//                    .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).list()
//                    .stream().map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList());
//
//            List<Long> current = teachingClassService.getTeachingClassIdsByRoomId(taskId,ruleRoomProhibit.getRoomId())lambdaQuery()
//                    .eq(TeachingClass::getTaskId, taskId)
//                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode()).list()
//                    .stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
//
//            ids = new ArrayList<>(CollectionUtils.intersection(ids, current));

            if (CollUtil.isNotEmpty(ids)) {
                List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService.getTeachingClassFix(taskId, ids)
                        .stream().filter(o -> o.getTimeCode().equals(ruleRoomProhibit.getTimeCode()))
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(classFix)) {
                    String msg = "教学班：" + classFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining(","))
                            + " 或课程规则将此课时设置为固排,设置禁排失败";
                    throw new BizException(5, msg);
                }
            }
        }
        return ruleRoomProhibitService.saveOrUpdate(ruleRoomProhibit);
    }


    /**
     * @param taskId:
     * @param schoolId:
     * @param roomId:
     * @param courseId:
     * @param classId:
     * @param teachingClassId:
     * @param teacherIds:
     * @Description: 固排时检查禁排课时
     * @Author: liufeng
     * @Date: 2023/12/6 20:16
     * @return:
     */
    @Override
    public ProhibitCheckVo checkProhibit(Integer taskId, String schoolId, Long roomId, Long courseId, String classId, Long teachingClassId, String teacherIds) {
        //获取教学班所有禁排信息
        //教室禁排课时
        List<RuleRoomProhibit> roomProhibits = new ArrayList<>();
        if (roomId != null) {
            roomProhibits = ruleRoomProhibitService.list(new LambdaQueryWrapper<RuleRoomProhibit>()
                    .eq(RuleRoomProhibit::getTaskId, taskId)
                    .eq(RuleRoomProhibit::getSchoolId, schoolId)
                    .eq(RuleRoomProhibit::getRoomId, roomId)
                    .eq(RuleRoomProhibit::getDeleted, Deleted.NOT.getCode()));
        }
        //课程禁排课时
        List<RuleCourseProhibit> courseProhibits = new ArrayList<>();
        if (courseId != null) {
            courseProhibits = ruleCourseProhibitMapper.getTeachingClassCourseProhibit(taskId, schoolId, courseId, teachingClassId);
        }


        List<RuleClassProhibit> classProhibits = new ArrayList<>();
        //行政班禁排课时
        if (StrUtil.isNotEmpty(classId)) {
            String[] split = classId.split(",");
            List<String> classIds = Arrays.stream(split).collect(Collectors.toList());
            classProhibits = ruleClassProhibitService.list(new LambdaQueryWrapper<RuleClassProhibit>()
                    .eq(RuleClassProhibit::getTaskId, taskId)
                    .eq(RuleClassProhibit::getSchoolId, schoolId)
                    .in(RuleClassProhibit::getClassId, classIds)
                    .eq(RuleClassProhibit::getFlag, 2)
                    .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode()));
        }
        //教学班禁排课时
        List<RuleTeachingClassProhibit> teachingClassProhibits = new ArrayList<>();
        if (teachingClassId != null) {
            teachingClassProhibits = ruleTeachingClassProhibitService.list(new LambdaQueryWrapper<RuleTeachingClassProhibit>()
                    .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                    .eq(RuleTeachingClassProhibit::getSchoolId, schoolId)
                    .eq(RuleTeachingClassProhibit::getTeachingClassId, teachingClassId)
                    .eq(RuleTeachingClassProhibit::getFlag, 2)
                    .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode()));
        }
        List<RuleTeacherTime> teacherTimes = new ArrayList<>();
        //多教师
        if (StrUtil.isNotEmpty(teacherIds)) {
            List<String> tIds = Arrays.stream(teacherIds.split(",")).collect(Collectors.toList());
            teacherTimes = ruleTeacherTimeService.list(new LambdaQueryWrapper<RuleTeacherTime>()
                    .eq(RuleTeacherTime::getTaskId, taskId)
                    .eq(RuleTeacherTime::getSchoolId, schoolId)
                    .in(RuleTeacherTime::getTeacherId, tIds)
                    .eq(RuleTeacherTime::getFlag, 2)
                    .eq(RuleTeacherTime::getDeleted, Deleted.NOT.getCode()));
        }
        return new ProhibitCheckVo().setClassProhibits(classProhibits).setRoomProhibits(roomProhibits)
                .setCourseProhibits(courseProhibits).setTeacherProhibits(teacherTimes)
                .setTeachingClassProhibits(teachingClassProhibits);
    }

    /**
     * @param taskId:
     * @param fixDto:
     * @Description: 检查固排冲突
     * @Author: liufeng
     * @Date: 2023/12/7 16:40
     * @return:
     */
    @Override
    public FixVo getFixConflict(Integer taskId, List<FixDto> fixDto) {
        if (CollUtil.isEmpty(fixDto)) {
            return new FixVo().setSuccess(false).setMsg("固排为空");
        }
        Long teachingClassId = fixDto.get(0).getTeachingClassId();
        if (teachingClassId == null) {
            return new FixVo().setSuccess(false).setMsg("教学班id不能为空");
        }
        FixVo fixVo = new FixVo().setSuccess(true).setMsg("该课时可以设置固排");
        try {
            List<RuleUsable> rules = ruleUsableService.getByTask(taskId);
            //检测禁排冲突
            fixVo = checkProhibitConflict(taskId, fixDto, rules);
            if (!fixVo.getSuccess()) {
                return fixVo;
            }

            //检测固排冲突
            fixVo = checkFixConflict(taskId, fixDto);
            if (!fixVo.getSuccess()) {
                return fixVo;
            }
            return fixVo;
        } catch (Exception e) {
            log.error("固排时检测异常：", e);
            return new FixVo().setSuccess(false).setMsg("固排时检测异常");
        }

    }

    /**
     * @param taskId:
     * @Description: 获取教师统一设置
     * @Author: liufeng
     * @Date: 2023/12/7 18:34
     * @return:
     */
    @Override
    public RuleTeacherSetting getTeacherSetting(Integer taskId) {
        return ruleTeacherSettingService.lambdaQuery().eq(RuleTeacherSetting::getTaskId, taskId).one();
    }

    /**
     * @param ruleTeacherSetting:
     * @Description: 修改教师统一设置
     * @Author: liufeng
     * @Date: 2023/12/7 18:51
     * @return:
     */
    @Override
    public Boolean setTeacherSetting(RuleTeacherSetting ruleTeacherSetting) {
        return ruleTeacherSettingService.saveOrUpdate(ruleTeacherSetting);
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param term:
     * @param teacherId:
     * @Description: 获取教师禁排
     * @Author: liufeng
     * @Date: 2023/12/7 19:06
     * @return:
     */
    @Override
    public List<RuleTeacherTime> getTeacherProhibit(Integer taskId, String schoolId, String term, Integer teacherId) {
        return ruleTeacherTimeService.lambdaQuery()
                .eq(RuleTeacherTime::getTaskId, taskId)
                .eq(RuleTeacherTime::getSchoolId, schoolId)
                .eq(RuleTeacherTime::getTerm, term)
                .eq(RuleTeacherTime::getFlag, 2)
                .eq(RuleTeacherTime::getTeacherId, teacherId)
                .eq(RuleTeacherTime::getDeleted, Deleted.NOT.getCode())
                .list();
    }

    /**
     * @param taskId:
     * @param ruleTeacherTime:
     * @Description: 设置教师禁排
     * @Author: liufeng
     * @Date: 2023/12/7 19:17
     * @return:
     */
    @Override
    public boolean setTeacherTimeProhibit(Integer taskId, RuleTeacherTime ruleTeacherTime) {
        if (ruleTeacherTime.getDeleted() == Deleted.NOT.getCode()) {
            //多教师版本
            //获取教师的教学班
            List<TeachingClassTeacher> teachingClassTeachers = teachingClassTeacherService.lambdaQuery()
                    .eq(TeachingClassTeacher::getTeacherId, ruleTeacherTime.getTeacherId())
                    .eq(TeachingClassTeacher::getDeleted, Deleted.NOT.getCode()).list();
            if (CollUtil.isNotEmpty(teachingClassTeachers)) {
                //获取教学班的固排
                List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService
                        .getTeachingClassFixByTeachingClassAndType(taskId, teachingClassTeachers)
                        .stream().filter(o -> o.getTimeCode().equals(ruleTeacherTime.getTimeCode()))
                        .collect(Collectors.toList());

//                List<Long> ids = teachingClassTeacherService.lambdaQuery()
//                        .eq(TeachingClassTeacher::getTeacherId, ruleTeacherTime.getTeacherId())
//                        .eq(TeachingClassTeacher::getDeleted, Deleted.NOT.getCode()).list()
//                        .stream().map(TeachingClassTeacher::getTeachingClassId).distinct().collect(Collectors.toList());
//                List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService.getTeachingClassFix(taskId, ids)
//                        .stream().filter(o -> o.getTimeCode().equals(ruleTeacherTime.getTimeCode()))
//                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(classFix)) {
                    String msg = "教学班：" + classFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                            + "或课程规则将此课时设置为固排,设置禁排失败";
                    throw new BizException(5, msg);
                }
            }
        }
        return ruleTeacherTimeService.saveOrUpdate(ruleTeacherTime);
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param classId:
     * @Description: 获取行政班禁排
     * @Author: liufeng
     * @Date: 2023/12/7 20:18
     * @return:
     */
    @Override
    public List<RuleClassProhibit> getClassProhibit(Integer taskId, String schoolId, Long classId) {
        return ruleClassProhibitService.lambdaQuery()
                .eq(RuleClassProhibit::getTaskId, taskId)
                .eq(RuleClassProhibit::getSchoolId, schoolId)
                .eq(RuleClassProhibit::getClassId, classId)
                .eq(RuleClassProhibit::getFlag, 2)
                .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode())
                .list();
    }

    /**
     * @param taskId:
     * @param ruleClassProhibit:
     * @Description: 设置行政班禁排
     * @Author: liufeng
     * @Date: 2023/12/7 20:21
     * @return:
     */
    @Override
    public boolean setClassProhibit(Integer taskId, RuleClassProhibit ruleClassProhibit) {
        if (ruleClassProhibit.getDeleted() == Deleted.NOT.getCode()) {
            //获取教学班
            List<Long> ids = teachingClassService.lambdaQuery()
                    .like(TeachingClass::getClassId, ruleClassProhibit.getClassId())
                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
            if (CollUtil.isEmpty(ids)) {
                return ruleClassProhibitService.saveOrUpdate(ruleClassProhibit);
            }
            //获取教学班固排
            List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService.getTeachingClassFix(taskId, ids)
                    .stream().filter(o -> o.getTimeCode().equals(ruleClassProhibit.getTimeCode()))
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(classFix)) {
                String msg = "政班关联的教学班：" + classFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                        + " 或课程规则将此课时设置为固排,设置禁排失败";
                throw new BizException(5, msg);
            }
        }
        return ruleClassProhibitService.saveOrUpdate(ruleClassProhibit);
    }

    @Override
    public List<RuleTeachingClassProhibit> getTeachingClassProhibit(Integer taskId, String schoolId, Long teachingClassId) {
        return ruleTeachingClassProhibitService.lambdaQuery()
                .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                .eq(RuleTeachingClassProhibit::getSchoolId, schoolId)
                .eq(RuleTeachingClassProhibit::getTeachingClassId, teachingClassId)
                .eq(RuleTeachingClassProhibit::getFlag, 2)
                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                .list();
    }

    @Override
    public boolean setTeachingClassProhibit(Integer taskId, RuleTeachingClassProhibit ruleTeachingClassProhibit) {
        if (ruleTeachingClassProhibit.getDeleted() == Deleted.NOT.getCode()) {
            //获取教学班固排
            List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService.getTeachingClassFix(taskId, Collections.singletonList(ruleTeachingClassProhibit.getTeachingClassId()))
                    .stream().filter(o -> o.getTimeCode().equals(ruleTeachingClassProhibit.getTimeCode()))
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(classFix)) {
                String msg = "教学班：" + classFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                        + " 或课程规则将此课时设置为固排,设置禁排失败";
                throw new BizException(5, msg);
            }
        }
        return ruleTeachingClassProhibitService.saveOrUpdate(ruleTeachingClassProhibit);
    }

    /**
     * @param taskId:
     * @Description: 获取所有基础规则
     * @Author: liufeng
     * @Date: 2023/12/12 10:50
     * @return:
     */
    @Override
    public List<RuleUsable> getBaseRule(Integer taskId) {
        return ruleUsableMapper.getByTaskId(taskId);
    }

    /**
     * @param taskId:
     * @param ruleUsableList:
     * @Description: 设置基础规则
     * @Author: liufeng
     * @Date: 2023/12/12 10:54
     * @return:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setBaseRule(Integer taskId, List<RuleUsable> ruleUsableList) {

        ruleUsableService.updateBatchById(ruleUsableList);

        //根据规则修改排课状态
//        List<Integer> enableTypes = ruleUsableList.stream().filter(o ->
//                         "b".equals(o.getOption())
//                        && (o.getCode() == 14 || o.getCode() == 15
//                        || o.getCode() == 16 || o.getCode() == 17 || o.getCode() == 18))
//                .peek(o -> {
//                    switch (o.getCode()){
//                        case 14: o.setCode(1);
//                            break;
//                        case 15: o.setCode(2);
//                            break;
//                        case 16: o.setCode(3);
//                            break;
//                        case 17: o.setCode(4);
//                            break;
//                        case 18: o.setCode(5);
//                            break;
//                    }
//                })
//                .map(RuleUsable::getCode)
//                .collect(Collectors.toList());

//        if (CollUtil.isNotEmpty(enableTypes)){
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        if (taskInfo != null && taskInfo.getDeleted() == Deleted.NOT.getCode()) {
            //哪些教学班有规则
            List<Long> ids = ruleTeachingClassProhibitMapper.getRulesClass(taskId, Deleted.NOT.getCode());
            if (CollUtil.isNotEmpty(ids)) {
                //更新排课状态
                arrangeCourseService.manualAdjustmentUpdateRule(taskInfo.getSchoolId(), taskInfo.getTerm(), taskId, null, ids);
            }
        }
//        }
        return true;
    }

    /**
     * @param taskId:
     * @param fixDtos:
     * @Description: 设置固排
     * @Author: liufeng
     * @Date: 2023/12/7 9:54
     * @return:
     */
    @Override
    public FixVo setFix(Integer taskId, String schoolId, String term, List<FixDto> fixDtos) {
        if (CollUtil.isEmpty(fixDtos)) {
            return new FixVo().setSuccess(false).setMsg("固排为空");
        }
        Long teachingClassId = fixDtos.get(0).getTeachingClassId();
        if (teachingClassId == null) {
            return new FixVo().setSuccess(false).setMsg("教学班id不能为空");
        }

        //取消
//        if (fixDtos.get(0).getDeleted() == Deleted.YES.getCode()){
//            List<Long> teachingClassIds = fixDtos.stream().map(FixDto::getTeachingClassId).collect(Collectors.toList());
//            ruleTeachingClassProhibitService.lambdaUpdate()
//                    .eq(RuleTeachingClassProhibit::getTaskId,taskId)
//                    .in(RuleTeachingClassProhibit::getTeachingClassId,teachingClassIds)
//                    .eq(RuleTeachingClassProhibit::getFlag,1)
//                    .set(RuleTeachingClassProhibit::getDeleted,Deleted.YES.getCode())
//                    .remove();
//            return new FixVo().setSuccess(true).setMsg("取消固排成功");
//        }

        //检查课时是否合法
        String timeCodePattern = getTimeCodePattern(taskId, schoolId, term);


        List<String> timeCodes = fixDtos.stream().map(FixDto::getTimeCode).collect(Collectors.toList());
        String dayNum = "";
        List<Integer> period = new ArrayList<>();
        for (String timeCode : timeCodes) {
            if (!Pattern.matches(timeCodePattern, timeCode)) {
                return new FixVo().setSuccess(false).setMsg("固排时间" + timeCode + "超出课时方案");
            }
            if (StrUtil.isEmpty(dayNum)) {
                dayNum = timeCode.substring(0, 2);
            }
            period.add(Integer.valueOf(timeCode.substring(2)));
        }

        //不允许连上跨上下午
        Integer count = periodSchemeMapper.fixPeriodSchemeCheck(taskId, schoolId, term, dayNum, period);

        if (count != null && count > 1) {
            return new FixVo().setSuccess(false).setMsg("连排时间禁止跨上下午");
        }

        //设置固排
        FixVo fixVo = new FixVo().setSuccess(true).setMsg("设置固排成功");
        try {
            synchronized (this) {
                List<RuleUsable> rules = ruleUsableService.getByTask(taskId);
                //检测禁排冲突
                fixVo = checkProhibitConflict(taskId, fixDtos, rules);
                if (!fixVo.getSuccess()) {
                    return fixVo;
                }

                //检测固排冲突
                fixVo = checkFixConflict(taskId, fixDtos);
                if (!fixVo.getSuccess()) {
                    return fixVo;
                }


                //都没有冲突
                //设置教学班固排课时
                List<RuleTeachingClassProhibit> add = new ArrayList<>();
                for (FixDto fixDto : fixDtos) {
                    add.add(new RuleTeachingClassProhibit()
                            .setTaskId(taskId).setTeachingClassId(teachingClassId)
                            .setFlag(1).setSchoolId(fixDto.getSchoolId()).setTimeCode(fixDto.getTimeCode())
                            .setType(fixDto.getType()).setDeleted(Deleted.NOT.getCode())
                            .setFixGroup(fixDto.getFixGroup())
                            .setHourType(fixDto.getHourType()));
                }

                ruleTeachingClassProhibitService.saveBatch(add);


            }
            //更新排课状态
//            arrangeCourseService.manualAdjustmentUpdate(schoolId, term, taskId, null, teachingClassId);
            arrangeCourseService.manualAdjustmentUpdateRule(schoolId, term, taskId, null, Collections.singletonList(teachingClassId));


            return fixVo;
        } catch (Exception e) {
            log.error("设置固排出错：", e);
            return new FixVo().setSuccess(false).setMsg(e.getMessage());
        }
    }

    @Override
    public Boolean removeFix(Integer taskId, String schoolId, String term, List<RuleTeachingClassProhibit> ruleList) {
        boolean res = ruleTeachingClassProhibitService.removeBatchByIds(ruleList);
        //更新排课状态
        Long teachingClassId = ruleList.get(0).getTeachingClassId();
//        arrangeCourseService.manualAdjustmentUpdate(schoolId, term, taskId, null, teachingClassId);
        arrangeCourseService.manualAdjustmentUpdateRule(schoolId, term, taskId, null, Collections.singletonList(teachingClassId));

        return res;
    }


    /**
     * @param taskId:
     * @param fixDtos:
     * @param rules:
     * @Description: 判断规则开启状态 统计排课结果
     * @Author: liufeng
     * @Date: 2024/2/2 17:21
     * @return:
     */
    @Override
    public FixVo checkProhibitConflictWithRule(Integer taskId, List<FixDto> fixDtos, List<RuleUsable> rules) {
        //todo 根据规则来判断
        FixVo fixVo = new FixVo().setSuccess(true);
        for (FixDto fixDto : fixDtos) {
            String schoolId = fixDto.getSchoolId();
            String timeCode = fixDto.getTimeCode();
            Long teachingClassId = fixDto.getTeachingClassId();
            //教学班禁排课时
            if (teachingClassId != null
                    && !"a".equals(rules.stream().filter(o -> o.getCode() == 10)
                    .collect(Collectors.toList()).get(0).getOption())) {
                List<String> codes = ruleTeachingClassProhibitMapper.fixCheck(taskId, teachingClassId, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该教学班已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //教师禁排课时
            if (StrUtil.isNotEmpty(fixDto.getTeacherIds())
                    && !"a".equals(rules.stream().filter(o -> o.getCode() == 7)
                    .collect(Collectors.toList()).get(0).getOption())) {
                List<String> teacherIds = Arrays.stream(fixDto.getTeacherIds().split(",")).collect(Collectors.toList());
                List<String> codes = ruleTeacherTimeMapper.fixCheck(taskId, teacherIds, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该教学班老师已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //课程禁排课时
            if (fixDto.getCourseId() != null
                    && !"a".equals(rules.stream().filter(o -> o.getCode() == 11)
                    .collect(Collectors.toList()).get(0).getOption())) {
                List<String> codes = ruleCourseProhibitMapper.fixCheck(taskId, fixDto.getCourseId(), schoolId, fixDto.getTeachingClassId(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该课程已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //行政班禁排课时
            if (fixDto.getClassId() != null
                    && !"a".equals(rules.stream().filter(o -> o.getCode() == 9)
                    .collect(Collectors.toList()).get(0).getOption())) {
                String[] split = fixDto.getClassId().split(",");
                List<String> classIds = Arrays.stream(split).collect(Collectors.toList());
                List<String> codes = ruleClassProhibitMapper.fixCheck(taskId, classIds, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该行政班已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //教室禁排课时
            if (fixDto.getRoomId() != null
                    && !"a".equals(rules.stream().filter(o -> o.getCode() == 6)
                    .collect(Collectors.toList()).get(0).getOption())) {
                List<String> codes = ruleRoomProhibitMapper.fixCheck(taskId, fixDto.getRoomId(), schoolId, Deleted.NOT.getCode());
                if (codes.contains(timeCode)) {
                    return new FixVo().setSuccess(false).setMsg("该教学班上课教室已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
        }

        return fixVo;
    }


    /**
     * @param taskId:
     * @param fixDtos:
     * @Description: 检测该教学班要设置的固排课时 是否与其他禁排课时冲突
     * @Author: liufeng
     * @Date: 2023/12/7 14:25
     * @return:
     */
    @Override
    public FixVo checkProhibitConflict(Integer taskId, List<FixDto> fixDtos, List<RuleUsable> rules) {
        FixVo fixVo = new FixVo().setSuccess(true);
        for (FixDto fixDto : fixDtos) {
            String schoolId = fixDto.getSchoolId();
            String timeCode = fixDto.getTimeCode();
            Long teachingClassId = fixDto.getTeachingClassId();
            //课时禁排
            if (StrUtil.isNotEmpty(timeCode)) {
                List<String> codes = ruleTimeProhibitService.lambdaQuery()
                        .eq(RuleTimeProhibit::getTaskId, taskId)
                        .eq(RuleTimeProhibit::getDeleted, Deleted.NOT.getCode())
                        .list()
                        .stream().map(RuleTimeProhibit::getTimeCode)
                        .distinct().collect(Collectors.toList());
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("课时禁排已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //教学班禁排课时
            if (teachingClassId != null) {
                List<String> codes = ruleTeachingClassProhibitMapper.fixCheck(taskId, teachingClassId, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该教学班已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //教师禁排课时
            if (StrUtil.isNotEmpty(fixDto.getTeacherIds())) {
                //多教师版本
                List<String> teacherIds = Arrays.stream(fixDto.getTeacherIds().split(",")).collect(Collectors.toList());
                List<String> codes = ruleTeacherTimeMapper.fixCheck(taskId, teacherIds, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该教学班老师已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //课程禁排课时
            if (fixDto.getCourseId() != null) {
                List<String> codes = ruleCourseProhibitMapper.fixCheck(taskId, fixDto.getCourseId(), schoolId, fixDto.getTeachingClassId(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该课程已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //行政班禁排课时
            if (fixDto.getClassId() != null) {
                String[] split = fixDto.getClassId().split(",");
                List<String> classIds = Arrays.stream(split).collect(Collectors.toList());
                List<String> codes = ruleClassProhibitMapper.fixCheck(taskId, classIds, schoolId, Deleted.NOT.getCode(), 2);
                if (codes.contains(timeCode)) {
                    return fixVo.setSuccess(false).setMsg("该行政班已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
            //教室禁排课时
            if (fixDto.getRoomId() != null) {
                List<String> codes = ruleRoomProhibitMapper.fixCheck(taskId, fixDto.getRoomId(), schoolId, Deleted.NOT.getCode());
                if (codes.contains(timeCode)) {
                    return new FixVo().setSuccess(false).setMsg("该教学班上课教室已将"
                            + TimeCodeUtil.convert(timeCode)
                            + "课时设置为禁排");
                }
            }
        }

        return fixVo;
    }

    /**
     * @param taskId:
     * @param fixDtos:
     * @Description: 设置固排时检测该教学班是还可以设置
     * @Author: liufeng
     * @Date: 2023/12/7 14:24
     * @return:
     */
    private FixVo checkFixConflict(Integer taskId, List<FixDto> fixDtos) {
        FixDto fixDto = fixDtos.get(0);
        Long teachingClassId = fixDto.getTeachingClassId();
        String schoolId = fixDto.getSchoolId();
        Long roomId = fixDto.getRoomId();
        Long courseId = fixDto.getCourseId();
        String teacherIds = fixDto.getTeacherIds();
        Integer type = fixDto.getType();
        FixVo fixVo = new FixVo().setSuccess(true);
        //如果课时重复
        List<String> fTimeCodes = fixDtos.stream().map(FixDto::getTimeCode).collect(Collectors.toList());

        HashSet<Long> teachingClassIds = new HashSet<>();
        //在教室上课的教学班
        if (roomId != null) {
            teachingClassIds.addAll(teachingClassWeekMapper.getteachingClassByRoomId(taskId, roomId, Deleted.NOT.getCode()));
        }
        //在教师上课的教学班
        if (StrUtil.isNotEmpty(teacherIds)) {
            List<Long> teachers = Arrays.stream(teacherIds.split(",")).map(Long::valueOf).distinct().collect(Collectors.toList());
            teachingClassIds.addAll(teachingClassTeacherMapper.getTeachingClassByTeacherId(taskId, teachers, Deleted.NOT.getCode()));
        }
        //课程的教学班

        teachingClassIds.add(teachingClassId);


        //获取固排信息
        List<RuleTeachingClassProhibit> exist = ruleTeachingClassProhibitService.lambdaQuery()
                .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                .eq(RuleTeachingClassProhibit::getFlag, 1)
//                .eq(RuleTeachingClassProhibit::getHourType, fixDto.getHourType())
                .in(RuleTeachingClassProhibit::getTimeCode, fTimeCodes)
                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                .and(o -> o.in(RuleTeachingClassProhibit::getTeachingClassId, teachingClassIds)
                        .or()
                        .eq(RuleTeachingClassProhibit::getCourseId, courseId))
                .list();

        if (CollUtil.isNotEmpty(exist)) {
            //收集固排的课时
            List<String> timeCodes = exist.stream()
                    .map(RuleTeachingClassProhibit::getTimeCode)
                    .distinct()
                    .collect(Collectors.toList());
            timeCodes = timeCodes.stream().map(TimeCodeUtil::convert).collect(Collectors.toList());
            //固排信息根据类型分组
            List<Integer> types = exist.stream().map(RuleTeachingClassProhibit::getType)
                    .distinct().collect(Collectors.toList());
            AtomicReference<String> msg = new AtomicReference<>("");
            types.forEach(o -> msg.updateAndGet(v -> v + FixType.getByCode(o).getMsg() + ","));

//            fixVo.setSuccess(false).setMsg("其他规则(" + msg.get().substring(0, msg.get().length() - 1) +
//                    ")已经将此课时设置为固排，该教学班的教师或上课场地已在此课时设置了固排，课时重复，设置失败:" + String.join(",", timeCodes));

            fixVo.setSuccess(false).setMsg("该教学班的教师或上课场地的(" + msg.get().substring(0, msg.get().length() - 1) +
                    ")已经将此课时设置为固排，课时重复，设置失败:" + String.join(",", timeCodes));
        }


        long count = ruleTeachingClassProhibitService.count(
                new LambdaQueryWrapper<RuleTeachingClassProhibit>()
                        .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                        .eq(RuleTeachingClassProhibit::getSchoolId, schoolId)
                        .eq(RuleTeachingClassProhibit::getTeachingClassId, teachingClassId)
                        .eq(RuleTeachingClassProhibit::getFlag, 1)
                        .eq(RuleTeachingClassProhibit::getHourType, fixDto.getHourType())
                        .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                        .ne(RuleTeachingClassProhibit::getType, FixType.Course.getCode()));

        TeachingClassWeek week = teachingClassWeekService.lambdaQuery().eq(TeachingClassWeek::getTeachingClassId, teachingClassId)
                .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode())
                .eq(TeachingClassWeek::getHourType, fixDto.getHourType()).one();
        Integer weekNum = week.getWeekNum();
        Integer connectSection = week.getConnectSection();
        Integer connectNumber = week.getConnectNumber();


        long leave = 0;
        if (weekNum < connectSection * connectNumber) {
            leave = ((long) (weekNum / connectSection) * connectNumber) - count;
        } else {
            leave = weekNum - count;
        }

        if (leave - fixDtos.size() < 0) {
            fixVo.setSuccess(false).setMsg("该教学班固排课时设置已满");
        }
        return fixVo;
    }

    @Override
    public List<ClassVo> getClassVo(Integer taskId, String gradeId, Long majorId) {


        //通过年级专业筛选出对应行政班
        List<ClassInfo> list = classInfoService.lambdaQuery().eq(ClassInfo::getTaskId, taskId)
                .eq(StringUtils.isNotBlank(gradeId), ClassInfo::getGradeId, gradeId)
                .like(ObjUtil.isNotNull(majorId), ClassInfo::getMajorId, String.valueOf(majorId)).list();


        //获取培养方案对应学生
        List<PlanTeachingToStudent> planTeachingToStudentList = planTeachingStudentMapper.selectPlanTeachingToStudentList(taskId, Deleted.NOT.getCode());


        //通过行政班进行过滤，获取学生反想获取对应行政班
        List<PlanTeachingToStudent> planTeachingToStudents = planTeachingToStudentList.stream()
                .filter(p -> list.stream().anyMatch(o -> o.getClassId().equals(p.getClassId()))).collect(Collectors.toList());

        List<String> collect = planTeachingToStudents.stream().map(PlanTeachingToStudent::getClassId).distinct().collect(Collectors.toList());

        List<ClassInfo> classInfos2 = list.stream().filter(p -> collect.contains(p.getClassId())).collect(Collectors.toList());


        TaskInfo taskInfo = taskInfoService.getById(taskId);


        List<Room> roomList = roomMapper.selectRoomList(taskInfo.getSchoolId(), taskInfo.getTerm());


        List<ClassVo> classVos = new ArrayList<>();
        classInfos2.forEach(o -> {
            ClassVo classVo = new ClassVo();
            classVo.setClassId(o.getClassId());
            classVo.setClassName(o.getClassName());
            classVo.setClassNum((long) o.getStudentNumber());
            classVo.setGenderId(o.getGenderId());
            classVo.setGenderName(o.getGenderName());
            classVo.setCampusId(o.getCampusId());
            classVo.setCampusName(o.getCampusName());
            List<Room> rooms = roomList.stream().filter(p -> p.getRoomId().equals(o.getRoomId())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(rooms)) {
                Room room = rooms.get(0);
                classVo.setRoomId(room.getRoomId());
                classVo.setRoomName(room.getRoomName());
            }
            classVos.add(classVo);
        });
        return classVos;

    }

    @Override
    public Integer addTeachingClassByClass(Integer taskId, ClassInfoByClassInput classInfos) {
        List<ClassInfoVo> classInfoVos = classInfos.getFacultyClassInfoList();
        teachingClassService.deletedByClassInfos(taskId);
        return teachingClassService.addBatch(taskId, classInfoVos);
    }


    @Override
    public Integer addTeachingClassByMajor(Integer taskId, ClassInfoByMajorInput gradeInfos) {
        List<GradeVo> gradeInfoVos = gradeInfos.getFacultyClassInfoList();
        teachingClassService.deletedByClassInfos(taskId);
        return teachingClassService.addBatchByMajor(taskId, gradeInfoVos);
    }

    /**
     * 导入行政班
     *
     * @param importProhibit
     * @param read
     */
    public Result toClassProhibit(HttpServletResponse response, ImportProhibit importProhibit, List<Map<String, Object>> read) {
        Map<String, Long> classMap = new HashMap<>();
        List<String> titleList = Arrays.asList("行政班名称", "禁排时间");
        List<RuleClassProhibit> ruleClassProhibits = new ArrayList<>();
        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取全部行政班名称
        List<String> classNames = read.stream()
                .map(o -> o.get("行政班名称").toString())
                .distinct().collect(Collectors.toList());
        //获取全部行政班
        if (CollUtil.isNotEmpty(classNames)) {
            classMap = classInfoService.lambdaQuery()
                    .eq(ClassInfo::getTaskId, importProhibit.getTaskId())
                    .eq(ClassInfo::getSchoolId, importProhibit.getSchoolId())
                    .in(ClassInfo::getClassName, classNames)
                    .list()
                    .stream().collect(Collectors.toMap(ClassInfo::getClassName, ClassInfo::getId));
        }
        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        List<ProhibitDto> reason = new ArrayList<>();
        //遍历
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> teacherProhibit = read.get(i);
            String className = teacherProhibit.get("行政班名称").toString();
            String timeCodeProhibit = teacherProhibit.get("禁排时间").toString();

            if (!classMap.containsKey(className)) {
                reason.add(new ProhibitDto().setName(className).setReason("行政班不存在: " + className));
                continue;
//                throw new BizException(5, ("第" + (i + 4) + "行行政班不存在" + className));
            }

            if (StrUtil.isNotBlank(timeCodeProhibit)) {
                String[] split = timeCodeProhibit.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        reason.add(new ProhibitDto().setName(className)
                                .setTimeCode(timeCode).setReason("禁排时间超出课时方案: " + timeCode));
//                        throw new BizException(5, ("第" + (i + 4) + "排禁排时间" + timeCode + "超出课时方案"));
                    }
                }
            }

            //获取教学班
            List<Long> ids = teachingClassService.lambdaQuery()
                    .like(TeachingClass::getClassId, classMap.get(className))
                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());

            //获取教学班固排
            List<RuleTeachingClassProhibit> classFix = new ArrayList<>();
            if (CollUtil.isNotEmpty(ids)) {
                classFix = ruleTeachingClassProhibitService
                        .getTeachingClassFix(importProhibit.getTaskId(), ids);
            }

            if (StrUtil.isNotBlank(timeCodeProhibit)) {
                String[] splitProhibit = timeCodeProhibit.split("/");
                for (String timeCode : splitProhibit) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        continue;
                    }
                    //检测时间冲突
                    List<RuleTeachingClassProhibit> tempClassFix = classFix
                            .stream().filter(o -> o.getTimeCode().equals(timeCode))
                            .collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(tempClassFix)) {
                        String msg = "教学班：" + tempClassFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                                + "将" + timeCode +
                                "课时设置为固排,设置禁排失败";
                        reason.add(new ProhibitDto().setName(className)
                                .setTimeCode(timeCode).setReason(msg));
//                        throw new BizException(5, msg);
                        continue;
                    }
                    ruleClassProhibits.add(new RuleClassProhibit()
                            .setTaskId(importProhibit.getTaskId())
                            .setClassId(classMap.get(className))
                            .setTimeCode(timeCode)
                            .setFlag(2)
                            .setSchoolId(importProhibit.getSchoolId())
                            .setDeleted(Deleted.NOT.getCode()));
                }
            }
        }
        List<RuleClassProhibit> addList = new ArrayList<>();
        if (importProhibit.getIsCoverage()) {
            ruleClassProhibitService.lambdaUpdate().eq(RuleClassProhibit::getTaskId, importProhibit.getTaskId())
                    .set(RuleClassProhibit::getDeleted, Deleted.YES.getCode()).update();
            addList = ruleClassProhibits.stream().distinct().collect(Collectors.toList());
        } else {
            //获取已存在禁排
            List<RuleClassProhibit> existProhibit = ruleClassProhibitService.lambdaQuery()
                    .eq(RuleClassProhibit::getTaskId, importProhibit.getTaskId())
                    .eq(RuleClassProhibit::getFlag, 2)
                    .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode()).list();

            for (RuleClassProhibit ruleClassProhibit : ruleClassProhibits) {
                Optional<RuleClassProhibit> isCoverage = existProhibit.stream()
                        .filter(o -> o.getTimeCode().equals(ruleClassProhibit.getTimeCode())
                                && o.getClassId().equals(ruleClassProhibit.getClassId())).findFirst();
                if (!isCoverage.isPresent()) {
                    addList.add(ruleClassProhibit);
                }
            }
        }

        if (CollUtil.isNotEmpty(addList)) {
            ruleClassProhibitService.saveBatch(addList);
        }
        //输出到文档
        return writeToExcel(response, importProhibit.getTaskId(), reason);
    }


    /**
     * 导入教师禁排
     *
     * @param importProhibit
     * @param read
     */
    public Result toTeacherProhibit(HttpServletResponse response, ImportProhibit importProhibit, List<Map<String, Object>> read) {
        Map<String, Long> teacherMap = new HashMap<>();
        List<String> titleList = Arrays.asList("任课教师工号", "禁排时间");
        List<RuleTeacherTime> ruleTeacherTimes = new ArrayList<>();
        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取全部教师工号
        List<String> teacherCodes = read.stream()
                .map(o -> o.get("任课教师工号").toString())
                .distinct().collect(Collectors.toList());
        //获取全部教师
        if (CollUtil.isNotEmpty(teacherCodes)) {
            teacherMap = teacherService.lambdaQuery()
                    .eq(Teacher::getSchoolId, importProhibit.getSchoolId())
                    .eq(Teacher::getTerm, importProhibit.getTerm())
                    .in(Teacher::getBaseTeacherId, teacherCodes)
                    .eq(Teacher::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().collect(Collectors.toMap(Teacher::getBaseTeacherId, Teacher::getTeacherId));
        }
        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        List<ProhibitDto> reason = new ArrayList<>();

        //遍历
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> teacherProhibit = read.get(i);
            String teacherCode = teacherProhibit.get("任课教师工号").toString();
            String timeCodeProhibit = teacherProhibit.get("禁排时间").toString();

            if (!teacherMap.containsKey(teacherCode)) {
                reason.add(new ProhibitDto().setName(teacherCode).setReason("任课教师工号不存在: " + teacherCode));
                continue;
//                throw new BizException(5, ("第" + (i + 4) + "行任课教师工号不存在" + teacherCode));
            }

            if (StrUtil.isNotBlank(timeCodeProhibit)) {
                String[] split = timeCodeProhibit.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        reason.add(new ProhibitDto().setName(teacherCode)
                                .setTimeCode(timeCode).setReason("禁排时间超出课时方案: " + timeCode));
//                        throw new BizException(5, ("第" + (i + 4) + "排禁排时间" + timeCode + "超出课时方案"));
                    }
                }
            }

            //获取教学班
            List<Long> ids = teachingClassTeacherService.lambdaQuery()
                    .eq(TeachingClassTeacher::getTeacherId, teacherMap.get(teacherCode))
                    .eq(TeachingClassTeacher::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().map(TeachingClassTeacher::getTeachingClassId).distinct().collect(Collectors.toList());
            //获取教学班固排
            List<RuleTeachingClassProhibit> classFix = new ArrayList<>();
            if (CollUtil.isNotEmpty(ids)) {
                classFix = ruleTeachingClassProhibitService
                        .getTeachingClassFix(importProhibit.getTaskId(), ids);
            }

            if (StrUtil.isNotBlank(timeCodeProhibit)) {
                String[] splitProhibit = timeCodeProhibit.split("/");
                for (String timeCode : splitProhibit) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        continue;
                    }
                    //检测时间冲突
                    List<RuleTeachingClassProhibit> tempClassFix = classFix
                            .stream().filter(o -> o.getTimeCode().equals(timeCode))
                            .collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(tempClassFix)) {
                        String msg = "教学班：" + tempClassFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                                + "将" + timeCode +
                                "课时设置为固排,设置禁排失败";
                        reason.add(new ProhibitDto().setName(teacherCode)
                                .setTimeCode(timeCode).setReason(msg));
//                        throw new BizException(5, msg);
                        continue;
                    }
                    ruleTeacherTimes.add(new RuleTeacherTime()
                            .setTaskId(importProhibit.getTaskId())
                            .setTeacherId(teacherMap.get(teacherCode))
                            .setTimeCode(timeCode)
                            .setFlag(2)
                            .setSchoolId(importProhibit.getSchoolId())
                            .setTerm(importProhibit.getTerm()));
                }
            }
        }
        List<RuleTeacherTime> addList = new ArrayList<>();
        if (importProhibit.getIsCoverage()) {
            ruleTeacherTimeService.lambdaUpdate().eq(RuleTeacherTime::getTaskId, importProhibit.getTaskId())
                    .remove();
            addList = ruleTeacherTimes.stream().distinct().collect(Collectors.toList());
        } else {
            //获取已存在禁排
            List<RuleTeacherTime> existProhibit = ruleTeacherTimeService.lambdaQuery()
                    .eq(RuleTeacherTime::getTaskId, importProhibit.getTaskId())
                    .eq(RuleTeacherTime::getFlag, 2)
                    .eq(RuleTeacherTime::getDeleted, Deleted.NOT.getCode()).list();

            for (RuleTeacherTime ruleTeacherTime : ruleTeacherTimes) {
                Optional<RuleTeacherTime> isCoverage = existProhibit.stream().filter(o -> o.getTimeCode().equals(ruleTeacherTime.getTimeCode()) && o.getTeacherId().equals(ruleTeacherTime.getTeacherId())).findFirst();
                if (!isCoverage.isPresent()) {
                    addList.add(ruleTeacherTime);
                }
            }
        }

        if (CollUtil.isNotEmpty(addList)) {
            ruleTeacherTimeService.saveBatch(addList);
        }
        //输出到文档
        return writeToExcel(response, importProhibit.getTaskId(), reason);
    }


    /**
     * 导入教学班禁排
     *
     * @param importProhibit
     * @param read
     */
    public Result toTeachingClassProhibit(HttpServletResponse response, ImportProhibit importProhibit, List<Map<String, Object>> read) {
        List<TeachingClass> teachingClassList = new ArrayList<>();
        Map<String, Long> teachingClassMap = new HashMap<>();
        List<TeachingClassWeek> teachingClassWeeks = new ArrayList<>();
        List<TeachingClassTeacher> teachingClassTeachers = new ArrayList<>();
        Map<Long, List<TeachingClassTeacher>> teacherMap = new HashMap<>();
        List<String> titleList = Arrays.asList("教学班名", "课时时间", "固/禁排", "授课类型");
        List<RuleTeachingClassProhibit> ruleTeachingClassProhibits = new ArrayList<>();

        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取全部教学班名
        List<String> teachingClassNames = read.stream()
                .map(o -> o.get("教学班名").toString())
                .distinct().collect(Collectors.toList());
        //获取全部教学班 教师  设置
        if (CollUtil.isNotEmpty(teachingClassNames)) {
            teachingClassList = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getTaskId, importProhibit.getTaskId())
                    .in(TeachingClass::getTeachingClassName, teachingClassNames)
                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                    .eq(TeachingClass::getIsEnable, 0)
                    .list();
            if (CollUtil.isNotEmpty(teachingClassList)) {
                teachingClassWeeks = teachingClassWeekService.lambdaQuery()
                        .in(TeachingClassWeek::getTeachingClassId, teachingClassList.stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList()))
                        .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).list();
                teachingClassTeachers = teachingClassTeacherService.lambdaQuery()
                        .in(TeachingClassTeacher::getTeachingClassId, teachingClassList.stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList()))
                        .eq(TeachingClassTeacher::getDeleted, Deleted.NOT.getCode()).list();
                teachingClassMap = teachingClassList
                        .stream()
                        .collect(Collectors.toMap(TeachingClass::getTeachingClassName, TeachingClass::getTeachingClassId));
                teacherMap = teachingClassTeachers.stream().collect(Collectors.groupingBy(TeachingClassTeacher::getTeachingClassId));
            }
        }
        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        List<ProhibitDto> reason = new ArrayList<>();
        //如果是覆盖  删除之前的教学班固排信息
        if (importProhibit.getIsCoverage()) {
            TransactionStatus status = transactionManager.getTransaction(def);
            try {
                ruleTeachingClassProhibitService.lambdaUpdate()
                        .eq(RuleTeachingClassProhibit::getTaskId, importProhibit.getTaskId())
                        .eq(RuleTeachingClassProhibit::getFlag, 1)
                        .eq(RuleTeachingClassProhibit::getType, FixType.TeachingClass.getCode())
                        .remove();

                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                log.error("导入教学班失败：", e);
                throw new BizException(e.getMessage());
            }
        }

        //禁排
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> teachingClassProhibit = read.get(i);

            String teachingClassName = teachingClassProhibit.get("教学班名").toString();
            String timeCodes = teachingClassProhibit.get("课时时间") == null ? "" : teachingClassProhibit.get("课时时间").toString();


            if (!teachingClassMap.containsKey(teachingClassName)) {
                reason.add(new ProhibitDto().setName(teachingClassName)
                        .setReason("第" + (i + 4) + "行教学班名不存在"));
                continue;
            }

            if ("2".equals(teachingClassProhibit.get("固/禁排").toString())) {

                //获取教学班
                List<Long> ids = Collections.singletonList(teachingClassMap.get(teachingClassName));
                //获取教学班固排 不区分授课方式
                List<RuleTeachingClassProhibit> classFix = ruleTeachingClassProhibitService
                        .getTeachingClassFix(importProhibit.getTaskId(), ids);
                //禁排时间
                if (StrUtil.isNotBlank(timeCodes)) {
                    String[] split = timeCodes.split("/");
                    for (String timeCode : split) {
                        if (!Pattern.matches(timeCodePattern, timeCode)) {
                            reason.add(new ProhibitDto().setName(teachingClassName)
                                    .setTimeCode(timeCode)
                                    .setReason("第" + (i + 4) + "课时时间" + timeCode + "超出课时方案"));
                            continue;
                        }
                        //检测时间冲突
                        List<RuleTeachingClassProhibit> tempClassFix = classFix
                                .stream().filter(o -> o.getTimeCode().equals(timeCode))
                                .collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(tempClassFix)) {
                            String msg = "教学班：" + tempClassFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                                    + "将" + timeCode +
                                    "课时设置为固排,设置禁排失败";
                            reason.add(new ProhibitDto().setName(teachingClassName)
                                    .setTimeCode(timeCode)
                                    .setReason(msg));
                            continue;

                        }
                        ruleTeachingClassProhibits.add(new RuleTeachingClassProhibit()
                                .setTaskId(importProhibit.getTaskId())
                                .setTeachingClassId(teachingClassMap.get(teachingClassName))
                                .setTimeCode(timeCode)
                                .setFlag(2)
                                .setSchoolId(importProhibit.getSchoolId())
                                .setDeleted(Deleted.NOT.getCode()));
                    }
                }

                TransactionStatus status1 = transactionManager.getTransaction(def);
                try {
                    List<RuleTeachingClassProhibit> addList = new ArrayList<>();
                    if (importProhibit.getIsCoverage()) {
                        ruleTeachingClassProhibitService.lambdaUpdate()
                                .eq(RuleTeachingClassProhibit::getTaskId, importProhibit.getTaskId())
                                .eq(RuleTeachingClassProhibit::getFlag, 2)
                                .remove();
                        addList = ruleTeachingClassProhibits.stream().distinct().collect(Collectors.toList());
                    } else {
                        List<RuleTeachingClassProhibit> existProhibit = ruleTeachingClassProhibitService.lambdaQuery()
                                .eq(RuleTeachingClassProhibit::getTaskId, importProhibit.getTaskId())
                                .eq(RuleTeachingClassProhibit::getFlag, 2)
                                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode()).list();
                        for (RuleTeachingClassProhibit ruleTeachingClassProhibit : ruleTeachingClassProhibits) {
                            Optional<RuleTeachingClassProhibit> isCoverage = existProhibit.stream()
                                    .filter(o -> o.getTimeCode().equals(ruleTeachingClassProhibit.getTimeCode())
                                            && o.getTeachingClassId().equals(ruleTeachingClassProhibit.getTeachingClassId())).findFirst();
                            if (!isCoverage.isPresent()) {
                                addList.add(ruleTeachingClassProhibit);
                            }
                        }
                    }


                    if (CollUtil.isNotEmpty(addList)) {
                        ruleTeachingClassProhibitService.saveBatch(addList);
                    }
                    transactionManager.commit(status1);
                } catch (Exception e) {
                    transactionManager.rollback(status1);
                    log.error("导入教学班失败：", e);
                    throw new BizException(e.getMessage());
                }
            }
        }

        List<RuleUsable> rules = ruleUsableService.getByTask(importProhibit.getTaskId());

        //固排
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> teachingClassProhibit = read.get(i);

            String teachingClassName = teachingClassProhibit.get("教学班名").toString();


            if (!teachingClassMap.containsKey(teachingClassName)) {
                reason.add(new ProhibitDto().setName(teachingClassName)
                        .setReason("第" + (i + 4) + "行教学班名不存在"));
                continue;
            }
            String timeCodes = teachingClassProhibit.get("课时时间") == null ? "" : teachingClassProhibit.get("课时时间").toString();

            if ("1".equals(teachingClassProhibit.get("固/禁排").toString())) {

                //固排时间
                if (StrUtil.isNotBlank(timeCodes)) {
                    String[] split = timeCodes.split("/");
                    boolean flag = true;
                    for (String timeCode : split) {
                        if (!Pattern.matches(timeCodePattern, timeCode)) {
                            flag = false;
                            reason.add(new ProhibitDto().setName(teachingClassName)
                                    .setTimeCode(timeCode)
                                    .setReason("第" + (i + 4) + "课时时间" + timeCode + "超出课时方案"));
//                            throw new BizException(5, ("第" + (i + 4) + "课时时间" + timeCode + "超出课时方案"));
                        }
                    }
                    if (!flag) {
                        continue;
                    }

                    //获取数据
                    Long tcId = teachingClassMap.get(teachingClassName);
                    int hourType = Integer.parseInt(teachingClassProhibit.get("授课类型").toString());
                    TeachingClassWeek week = teachingClassWeeks.stream().filter(o ->
                            Objects.equals(o.getTeachingClassId(), tcId)
                                    && o.getHourType() == hourType).findFirst().orElse(null);
                    if (week == null || week.getWeekNum() == null || week.getWeekNum() == 0) {
                        reason.add(new ProhibitDto().setName(teachingClassName)
                                .setHourType(teachingClassProhibit.get("授课类型").toString())
                                .setReason("第" + (i + 4) + "授课类型" + hourType + "不存在"));
                        continue;
                    }
                    if (week.getConnectSection() < split.length) {
                        reason.add(new ProhibitDto().setName(teachingClassName)
                                .setHourType(teachingClassProhibit.get("授课类型").toString())
                                .setReason("第" + (i + 4) + "行固排课时超过连上次数：" + week.getConnectSection()));
                        continue;
                    }

                    TeachingClass teachingClass = teachingClassList.stream().filter(o -> Objects.equals(o.getTeachingClassId(), tcId))
                            .findFirst().orElse(null);
                    //多教师版本
                    String teacherIds = teacherMap.get(tcId) == null ?
                            "" : teacherMap.get(tcId).stream()
                            .filter(o -> o.getTeacherType() == hourType)
                            .map(TeachingClassTeacher::getTeacherId)
                            .collect(Collectors.toList())
                            .stream().map(String::valueOf).collect(Collectors.joining(","));


                    /*
                     * 输入没有问题 检测是否固排
                     */
                    flag = true;


                    /*
                     * 检测禁排是否包含设置固排的课时
                     */

                    List<FixDto> fixDtoList = new ArrayList<>();
                    //如果禁排时间包含这行的固排时间  失败
                    String group = UUID.randomUUID().toString();
                    for (String timeCode : split) {
                        fixDtoList.add(new FixDto()
                                .setSchoolId(importProhibit.getSchoolId())
                                .setTeachingClassId(tcId)
                                .setClassId(teachingClass.getClassId())
                                .setTimeCode(timeCode)
                                .setCourseId(teachingClass.getCourseId())
                                .setRoomId(week.getRoomId())
                                .setTeacherIds(teacherIds)
                                .setType(FixType.TeachingClass.getCode())
                                .setFixGroup(group)
                                .setHourType(hourType)
                        );
                    }
                    FixVo fixVo = checkProhibitConflict(importProhibit.getTaskId(), fixDtoList, rules);

                    if (!fixVo.getSuccess()) {
                        flag = false;
                        String msg = "第" + (i + 4) + fixVo.getMsg() + ",设置固排失败";
                        reason.add(new ProhibitDto().setName(teachingClassName)
                                .setHourType(teachingClassProhibit.get("授课类型").toString())
                                .setReason(msg));

//                            throw new BizException(5, ("第" + (i + 4) + "课时时间" + timeCode + "超出课时方案"));
                    }

                    // 整行跳过
                    if (!flag) {
                        continue;
                    }


                    /*
                     * 是否还可以进行固排
                     */
                    FixVo fixVo1 = checkFixConflictImport(importProhibit.getTaskId(), fixDtoList, week);
                    if (!fixVo1.getSuccess()) {
                        String msg = "第" + (i + 4) + fixVo1.getMsg() + ",设置固排失败";
                        reason.add(new ProhibitDto().setName(teachingClassName)
                                .setHourType(teachingClassProhibit.get("授课类型").toString())
                                .setReason(msg));
                        continue;
                    }
                    //都没有冲突
                    //设置教学班固排课时
                    List<RuleTeachingClassProhibit> addList = new ArrayList<>();
                    for (FixDto fixDto : fixDtoList) {
                        addList.add(new RuleTeachingClassProhibit()
                                .setTaskId(importProhibit.getTaskId()).setTeachingClassId(tcId)
                                .setFlag(1).setSchoolId(fixDto.getSchoolId()).setTimeCode(fixDto.getTimeCode())
                                .setType(fixDto.getType()).setDeleted(Deleted.NOT.getCode())
                                .setFixGroup(fixDto.getFixGroup())
                                .setHourType(fixDto.getHourType()));
                    }
                    TransactionStatus status3 = transactionManager.getTransaction(def);
                    try {

                        List<RuleTeachingClassProhibit> existProhibit = ruleTeachingClassProhibitService.lambdaQuery()
                                .eq(RuleTeachingClassProhibit::getTaskId, importProhibit.getTaskId())
                                .eq(RuleTeachingClassProhibit::getFlag, 1)
                                .eq(RuleTeachingClassProhibit::getType, FixType.TeachingClass.getCode())
                                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode()).list();

                        addList = addList.stream()
                                .filter(o -> existProhibit.stream().noneMatch(p -> o.getTimeCode().equals(p.getTimeCode())
                                        && o.getTeachingClassId().equals(p.getTeachingClassId())
                                        && Objects.equals(o.getHourType(), p.getHourType())))
                                .distinct().collect(Collectors.toList());

                        if (CollUtil.isNotEmpty(addList)) {
                            ruleTeachingClassProhibitService.saveBatch(addList);
                            //跟新排课状态
                            List<Long> tcIds = addList.stream().map(RuleTeachingClassProhibit::getTeachingClassId)
                                    .distinct().collect(Collectors.toList());
//                            tcIds.forEach(o -> arrangeCourseService.manualAdjustmentUpdate(importProhibit.getSchoolId(), importProhibit.getTerm(), importProhibit.getTaskId(), null, o));
                            arrangeCourseService.manualAdjustmentUpdateRule(importProhibit.getSchoolId(), importProhibit.getTerm(), importProhibit.getTaskId(), null, tcIds);

                        }
                        transactionManager.commit(status3);
                    } catch (Exception e) {
                        transactionManager.rollback(status3);
                        log.error("导入教学班失败：", e);
                        throw new BizException(e.getMessage());
                    }
                }
            }
        }


        return writeToExcel(response, importProhibit.getTaskId(), reason);

    }

    private FixVo checkFixConflictImport(Integer taskId, List<FixDto> fixDtos, TeachingClassWeek week) {
        FixDto fixDto = fixDtos.get(0);
        Long teachingClassId = fixDto.getTeachingClassId();
        String schoolId = fixDto.getSchoolId();
        Integer type = fixDto.getType();
        FixVo fixVo = new FixVo().setSuccess(true);
        //如果课时重复
        List<String> fTimeCodes = fixDtos.stream().map(FixDto::getTimeCode).collect(Collectors.toList());
        List<String> timeCodes = ruleTeachingClassProhibitService.lambdaQuery()
                .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                .eq(RuleTeachingClassProhibit::getTeachingClassId, teachingClassId)
                .eq(RuleTeachingClassProhibit::getFlag, 1)
                .eq(RuleTeachingClassProhibit::getHourType, fixDto.getHourType())
                .in(RuleTeachingClassProhibit::getTimeCode, fTimeCodes)
                .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                .list()
                .stream().map(RuleTeachingClassProhibit::getTimeCode).distinct().collect(Collectors.toList());
        if (timeCodes.size() > 0) {
            timeCodes = timeCodes.stream().map(TimeCodeUtil::convert).collect(Collectors.toList());
            fixVo.setSuccess(false).setMsg("课时重复，设置失败:" + String.join(",", timeCodes));
        }


        long count = ruleTeachingClassProhibitService.count(
                new LambdaQueryWrapper<RuleTeachingClassProhibit>()
                        .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                        .eq(RuleTeachingClassProhibit::getSchoolId, schoolId)
                        .eq(RuleTeachingClassProhibit::getTeachingClassId, teachingClassId)
                        .eq(RuleTeachingClassProhibit::getFlag, 1)
                        .eq(RuleTeachingClassProhibit::getHourType, fixDto.getHourType())
                        .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                        .ne(RuleTeachingClassProhibit::getType, FixType.Course.getCode()));

        Integer weekNum = week.getWeekNum();
        Integer connectSection = week.getConnectSection();
        Integer connectNumber = week.getConnectNumber();


        long leave = 0;
        if (weekNum < connectSection * connectNumber) {
            leave = ((long) (weekNum / connectSection) * connectNumber) - count;
        } else {
            leave = weekNum - count;
        }

        if (leave - fixDtos.size() < 0) {
            fixVo.setSuccess(false).setMsg("该教学班固排课时不足");
        }
        return fixVo;
    }


    /**
     * @param importProhibit:
     * @param read:
     * @Description: 导入教室禁排
     * @Author: liufeng
     * @Date: 2023/12/8 16:58
     * @return:
     */
    public Result toRoomProhibit(HttpServletResponse response, ImportProhibit importProhibit, List<Map<String, Object>> read) {
        Map<String, Long> roomMap = new HashMap<>();
        List<String> titleList = Arrays.asList("教室名", "禁排时间");
        List<RuleRoomProhibit> ruleRoomProhibits = new ArrayList<>();

        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取全部教室名
        List<String> roomNames = read.stream()
                .map(o -> o.get("教室名").toString())
                .distinct().collect(Collectors.toList());
        //获取全部教室
        if (CollUtil.isNotEmpty(roomNames)) {
            roomMap = roomService.lambdaQuery()
                    .eq(Room::getSchoolId, importProhibit.getSchoolId())
                    .eq(Room::getTerm, importProhibit.getTerm())
                    .eq(Room::getDeleted, Deleted.NOT.getCode())
                    .in(Room::getRoomName, roomNames).list()
                    .stream().collect(Collectors.toMap(Room::getRoomName, Room::getRoomId));
        }
        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        List<ProhibitDto> reason = new ArrayList<>();

        //遍历
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> roomProhibit = read.get(i);
            String roomName = roomProhibit.get("教室名").toString();
            String timeCodes = roomProhibit.get("禁排时间").toString();

            if (!roomMap.containsKey(roomName)) {
                reason.add(new ProhibitDto().setName(roomName).setReason("第" + (i + 4) + "行教室名不存在: " + roomName));
                continue;
//                throw new BizException(5, ("第" + (i + 4) + "行教室名不存在" + roomName));
            }
            if (StrUtil.isNotBlank(timeCodes)) {
                String[] split = timeCodes.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        reason.add(new ProhibitDto().setName(roomName)
                                .setTimeCode(timeCode).setReason("禁排时间:" + timeCode + " 超出课时方案"));
//                        throw new BizException(5, ("第" + (i + 4) + "禁排时间" + timeCode + "超出课时方案"));
                    }
                }
            }
            //获取教学班
            List<Long> ids = teachingClassWeekService.lambdaQuery()
                    .eq(TeachingClassWeek::getRoomId, roomMap.get(roomName))
                    .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().map(TeachingClassWeek::getTeachingClassId).distinct().collect(Collectors.toList());

//            List<Long> current = teachingClassService.lambdaQuery()
//                    .eq(TeachingClass::getTaskId, importProhibit.getTaskId())
//                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode()).list()
//                    .stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());

//            ids = new ArrayList<>(CollectionUtils.intersection(ids, current));

            //获取教学班固排
            List<RuleTeachingClassProhibit> classFix = new ArrayList<>();
            if (CollUtil.isNotEmpty(ids)) {
                classFix = ruleTeachingClassProhibitService
                        .getTeachingClassFix(importProhibit.getTaskId(), ids);
            }

            //保存
            if (StrUtil.isNotBlank(timeCodes)) {
                String[] split = timeCodes.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        continue;
                    }
                    //检测时间冲突
                    List<RuleTeachingClassProhibit> tempClassFix = classFix
                            .stream().filter(o -> o.getTimeCode().equals(timeCode))
                            .collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(tempClassFix)) {
                        String msg = "教学班：" + tempClassFix.stream().map(RuleTeachingClassProhibit::getTeachingClassName).collect(Collectors.joining())
                                + "将" + timeCode +
                                "课时设置为固排,设置禁排失败";
                        reason.add(new ProhibitDto().setName(roomName)
                                .setTimeCode(timeCode).setReason(msg));
//                        throw new BizException(5, msg);
                        continue;
                    }
                    ruleRoomProhibits.add(new RuleRoomProhibit()
                            .setTaskId(importProhibit.getTaskId())
                            .setRoomId(roomMap.get(roomName))
                            .setTimeCode(timeCode)
                            .setSchoolId(importProhibit.getSchoolId())
                            .setTerm(importProhibit.getTerm())
                    );
                }
            }
        }

        if (importProhibit.getIsCoverage()) {
            ruleRoomProhibitService.lambdaUpdate().eq(RuleRoomProhibit::getTaskId, importProhibit.getTaskId()).remove();
            ruleRoomProhibits = ruleRoomProhibits.stream().distinct().collect(Collectors.toList());
        } else {
            List<RuleRoomProhibit> existProhibit = ruleRoomProhibitService.lambdaQuery()
                    .eq(RuleRoomProhibit::getTaskId, importProhibit.getTaskId())
                    .eq(RuleRoomProhibit::getDeleted, Deleted.NOT.getCode()).list();
            ruleRoomProhibits = ruleRoomProhibits.stream()
                    .filter(o -> existProhibit.stream().noneMatch(p -> p.getTimeCode().equals(o.getTimeCode()) && p.getRoomId().equals(o.getRoomId())))
                    .distinct().collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(ruleRoomProhibits)) {
            ruleRoomProhibitService.saveBatch(ruleRoomProhibits);
        }

        //输出到文档
        return writeToExcel(response, importProhibit.getTaskId(), reason);
    }

    private Result writeToExcel(HttpServletResponse response, Integer taskId, List<ProhibitDto> reason) {
        if (CollUtil.isEmpty(reason)) {
            return Result.ofSuccess();
        }
//        MyExcelUtils.exportExcel(reason,
//                "导入结果", "", ProhibitDto.class,
//                "导入结果" + System.currentTimeMillis(), response);
//        return Result.ofFail(400,999,"部分导入成功");

        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTaskName() + "/导入返回-" + System.currentTimeMillis() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        List<List<String>> rows = new ArrayList<>();
        rows.add(Arrays.asList("名称", "课时", "原因"));
        List<String> row;

        for (ProhibitDto item : reason) {
            row = Arrays.asList(item.getName(), item.getTimeCode(), item.getReason());
            rows.add(row);
        }
        writer.write(rows, false);
//        ExcelFormatUtil.setFont(writer);
        writer.setColumnWidth(-1, 20);
        writer.setDefaultRowHeight(20);
        writer.close();
        String data = GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;
        return Result.ofFail(400, 999, "部分导入失败，失败原因写入文档", data);
//        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel" + storePath;


    }

    /**
     * @param importProhibit:
     * @param read:
     * @Description: 导入时间禁排
     * @Author: liufeng
     * @Date: 2023/12/5 20:26
     * @return:
     */
    public Result toTimeProhibit(ImportProhibit importProhibit, List<Map<String, Object>> read) {

        List<String> titleList = Arrays.asList("禁排时间");
        List<RuleTimeProhibit> ruleTimeProhibits = new ArrayList<>();

        //判断模块是否符合要求
        boolean allColumnsMatch = titleList.containsAll(read.get(0).keySet());
        if (read.get(0).keySet().size() != titleList.size() || !allColumnsMatch ) {
            throw new BizException(5, "导入模板不匹配，请按照标准模板编辑后导入");
        }

        //获取timeCode正则表达式
        String timeCodePattern = getTimeCodePattern(importProhibit.getTaskId(), importProhibit.getSchoolId(), importProhibit.getTerm());

        //遍历
        for (int i = 0; i < read.size(); i++) {
            Map<String, Object> map = read.get(i);
            String timeCodes = map.get("禁排时间").toString();

            if (StrUtil.isNotBlank(timeCodes)) {
                String[] split = timeCodes.split("/");
                for (String timeCode : split) {
                    if (!Pattern.matches(timeCodePattern, timeCode)) {
                        throw new BizException(5, ("第" + (i + 4) + "行禁排时间" + timeCode + "超出课时方案"));
                    }
                    //检查固排 以下面的方法二选一
//                    setTimeProhibitCheck(importProhibit.getTaskId(), timeCode);

                    ruleTimeProhibits.add(new RuleTimeProhibit()
                            .setTimeCode(timeCode)
                            .setTaskId(importProhibit.getTaskId())
                            .setSchoolId(importProhibit.getSchoolId())
                            .setTerm(importProhibit.getTerm())
                            .setDeleted(Deleted.NOT.getCode()));
                }
            }
        }

        if (importProhibit.getIsCoverage()) {
            ruleTimeProhibitService.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, importProhibit.getTaskId()).remove();
            ruleTimeProhibits = ruleTimeProhibits.stream().distinct().collect(Collectors.toList());
        } else {
            List<RuleTimeProhibit> existProhibit = ruleTimeProhibitService.lambdaQuery().eq(RuleTimeProhibit::getTaskId, importProhibit.getTaskId())
                    .eq(RuleTimeProhibit::getDeleted, Deleted.NOT.getCode()).list();
            ruleTimeProhibits = ruleTimeProhibits.stream()
                    .filter(o -> existProhibit.stream().noneMatch(e -> e.getTimeCode().equals(o.getTimeCode())))
                    .collect(Collectors.toList());
        }

        if (CollUtil.isNotEmpty(ruleTimeProhibits)) {
            //不进行提示 将该课时相关的禁排 固排删除
            List<String> codes = ruleTimeProhibits.stream().filter(o -> o.getDeleted() == Deleted.NOT.getCode())
                    .map(RuleTimeProhibit::getTimeCode).collect(Collectors.toList());
            timeProhibitSuit(importProhibit.getTaskId(), codes, 0);
            ruleTimeProhibitService.saveBatch(ruleTimeProhibits);
        }
        return Result.ofSuccess();
    }

    /**
     * @param taskId:
     * @Description: 设置或导入课时禁排时 将相关的固排禁排规则删除
     * @Author: liufeng
     * @Date: 2023/12/8 13:36
     * @return:
     */
    private void timeProhibitSuit(Integer taskId, List<String> codes, int module) {
        //检测是否设置下面的流程
        if (module != 0) {
            ruleTimeProhibitService.lambdaUpdate()
                    .eq(RuleTimeProhibit::getTaskId, taskId)
                    .in(RuleTimeProhibit::getTimeCode, codes)
                    .remove();
        }


        if (module != FixType.Room.getCode()) {
            ruleRoomProhibitService.lambdaUpdate()
                    .eq(RuleRoomProhibit::getTaskId, taskId)
                    .in(RuleRoomProhibit::getTimeCode, codes)
                    .remove();
        }
        if (module != FixType.Teacher.getCode()) {
            ruleTeacherTimeService.lambdaUpdate()
                    .eq(RuleTeacherTime::getTaskId, taskId)
                    .in(RuleTeacherTime::getTimeCode, codes)
                    .remove();
        }
        //删除课程固排表信息
        if (module != FixType.Course.getCode()) {
            ruleCourseProhibitService.timeProhibitSuit(taskId, codes);
        }

        if (module != FixType.Class.getCode()) {
            ruleClassProhibitService.lambdaUpdate()
                    .eq(RuleClassProhibit::getTaskId, taskId)
                    .in(RuleClassProhibit::getTimeCode, codes)
                    .remove();
        }

        //筛选固排分组  删除固排
        if (module != FixType.TeachingClass.getCode()) {
            List<String> group = ruleTeachingClassProhibitService.lambdaQuery()
                    .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                    .in(RuleTeachingClassProhibit::getTimeCode, codes)
                    .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                    .eq(RuleTeachingClassProhibit::getFlag, 1).list()
                    .stream().map(RuleTeachingClassProhibit::getFixGroup).distinct()
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(group)) {
                ruleTeachingClassProhibitService.lambdaUpdate()
                        .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                        .in(RuleTeachingClassProhibit::getFixGroup, group)
                        .remove();
            }

            ruleTeachingClassProhibitService.lambdaUpdate()
                    .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                    .in(RuleTeachingClassProhibit::getTimeCode, codes)
                    .remove();
        }
    }

    /**
     * 获取最大节次的时间  并转化为正则表达式
     *
     * @param schoolId
     * @param term
     * @return
     */
    public String getTimeCodePattern(Integer taskId, String schoolId, String term) {
        List<RuleWeekDay> weekDays = this.getWeekDays(taskId, schoolId, term);
        OptionalInt maxPeriodSchemesSize = weekDays.stream()
                .mapToInt(day -> day.getPeriodSchemes().size())
                .max();

        //最大周次
        int maxWeek = 7;
        //最大节次
        int maxPeriod = maxPeriodSchemesSize.orElse(0);
        // 生成周次的正则表达式
        String weekRegex = maxWeek < 10 ? "(0[1-" + maxWeek + "])" : "(0[1-9]|1[0-" + (maxWeek - 10) + "])";
        // 生成节次的正则表达式
        String periodRegex = maxPeriod < 10 ? "(0[1-" + maxPeriod + "])" : "(0[1-9]|1[0-" + (maxPeriod - 10) + "])";
        return "^" + weekRegex + periodRegex + "$";
    }

    @Override
    public ClassInfoByMajorResponse getClassInfoByMajor(Integer taskId, String majorId, String gradeId, String keyWord, Integer currentPage, Integer pageSize) {

        List<GradeVo> gradeVos = new ArrayList<>();

        //通过taskid和gradeid 筛选出对应的年级
        List<TaskToGrade> taskToGrades = taskToGradeService.lambdaQuery()
                .eq(TaskToGrade::getTaskId, taskId)
                .eq(StrUtil.isNotBlank(gradeId), TaskToGrade::getGradeId, gradeId)
                .eq(TaskToGrade::getDeleted, Deleted.NOT.getCode()).list();


        //通过年级和专业id获取对应专业信息
        List<Major> majors = majorService.lambdaQuery().eq(Major::getTaskId, taskId)
                .eq(StrUtil.isNotBlank(majorId), Major::getBaseMajorId, majorId)
                .eq(StrUtil.isNotBlank(gradeId), Major::getGradeId, gradeId)
                .eq(Major::getDeleted, Deleted.NOT.getCode())
                .and(StrUtil.isNotBlank(keyWord), wrapper -> wrapper.like(Major::getMajorName, keyWord))
                .list();


        //通过年级获取对应行政班
        List<ClassInfo> classInfos = classInfoService.lambdaQuery().eq(ClassInfo::getTaskId, taskId)
                .eq(StrUtil.isNotBlank(gradeId), ClassInfo::getGradeId, gradeId).list();


        //获取对应课程
        List<Course> courses = courseMapper.getCourseList(taskId);


        Map<String, Long> courseMap = courses.stream().collect(Collectors.toMap(Course::getBaseCourseId, Course::getCourseId, (o1, o2) -> o1));


        //获取对应环节
        List<Segment> segments = segmentMapper.getSegmentList(taskId);

        Map<String, Long> segmentMap = segments.stream().collect(Collectors.toMap(Segment::getBaseSegmentId, Segment::getSegmentId, (o1, o2) -> o1));


        //获取未启用课程
        List<ClassCourseClose> classCourseCloseListCourse = classCourseCloseService.lambdaQuery().eq(ClassCourseClose::getTaskId, taskId)
                .eq(ClassCourseClose::getFlag, 1)
                .eq(ClassCourseClose::getDeleted, Deleted.YES.getCode()).list();


        //获取未启用环节
        List<ClassCourseClose> classCourseCloseListSegment = classCourseCloseService.lambdaQuery().eq(ClassCourseClose::getTaskId, taskId)
                .eq(ClassCourseClose::getFlag, 2)
                .eq(ClassCourseClose::getDeleted, Deleted.YES.getCode()).list();


        //获取培养计划对应学生
        List<PlanTeachingToStudent> planTeachingToStudentList = planTeachingStudentMapper.selectPlanTeachingToStudentList(taskId, Deleted.NOT.getCode());


        //获取培养方案对应课程
        List<PlanTeachingCourseSegment> planTeachingCourseSegments = planTeachingCourseSegmentMapper.selectPlanTeachingCourseSegmentList(taskId, Deleted.NOT.getCode());

        //获取培养方案
        List<PlanTeaching> planTeachings = planTeachingService.lambdaQuery().eq(PlanTeaching::getTaskId, taskId)
                .eq(PlanTeaching::getDeleted, Deleted.NOT.getCode()).list();


        Set<Major> majorSet = new HashSet<>();

        for (TaskToGrade taskToGrade : taskToGrades) {
            GradeVo gradeVo = new GradeVo();
            gradeVo.setGradeId(taskToGrade.getGradeId());
            gradeVo.setGradeName(taskToGrade.getGradeName());
            List<MajorVo> majorVos = new ArrayList<>();

            List<Major> majors1 = majors.stream().filter(p -> p.getGradeId().equals(taskToGrade.getGradeId()))
                    .distinct().collect(Collectors.toList());


            //通过专业来确定班级，在通过班级确定培养方案，在通过培养方案确定对应课程
            if (CollUtil.isNotEmpty(majors1)) {
                for (Major major : majors1) {
                    MajorVo majorVo = new MajorVo();
                    majorVo.setMajorId(major.getMajorId());
                    majorVo.setMajorName(major.getMajorName());
                    majorVo.setCampusId(major.getCampusId() != null ? major.getCampusId() : "");
                    majorVo.setCampusName(major.getCampusName() != null ? major.getCampusName() : "");

                    List<ClassInfo> classInfos1 = classInfos.stream()
                            .filter(p -> p.getMajorId().contains(String.valueOf(major.getMajorId()))
                                    && p.getGradeId().equals(taskToGrade.getGradeId())).collect(Collectors.toList());

                    if (CollUtil.isEmpty(classInfos1)) {
                        continue;
                    }

                    List<PlanTeachingToStudent> planTeachingToStudents = planTeachingToStudentList.stream()
                            .filter(p -> classInfos1.stream().anyMatch(o -> o.getClassId().equals(p.getClassId()))).collect(Collectors.toList());

                    List<String> collect = planTeachingToStudents.stream().map(PlanTeachingToStudent::getClassId).distinct().collect(Collectors.toList());

                    List<ClassInfo> classInfos2 = classInfos1.stream().filter(p -> collect.contains(p.getClassId())).collect(Collectors.toList());

                    List<ClassInfo> classInfos3 = classInfos2.stream().filter(p -> Objects.isNull(p.getRoomId()))
                            .collect(Collectors.toList());

                    List<String> collect1 = planTeachingToStudents.stream().map(PlanTeachingToStudent::getBaseTeachingPlanId)
                            .distinct().collect(Collectors.toList());


                    List<PlanTeaching> pTeaching = planTeachings.stream()
                            .filter(p -> collect1.contains(p.getBaseTeachingPlanId()))
                            .collect(Collectors.toList());

                    if (CollUtil.isEmpty(pTeaching)) {
                        continue;
                    }

                    if (!majorSet.contains(major)) {
                        majorSet.add(major);
                    }


                    Set<Long> baseCourse = new HashSet<>();
                    Set<Long> baseSegment = new HashSet<>();
                    if (CollUtil.isNotEmpty(pTeaching)) {
                        for (PlanTeaching planTeaching : pTeaching) {

                            List<PlanTeachingCourseSegment> pTeachingCourseSegments = planTeachingCourseSegments.stream()
                                    .filter(p -> p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId())
                                            && p.getFlag() == 1).collect(Collectors.toList());


                            Set<String> courseId = new HashSet<>();
                            if (CollUtil.isNotEmpty(pTeachingCourseSegments)) {
                                for (PlanTeachingCourseSegment pTeachingCourseSegment : pTeachingCourseSegments) {
                                    if (!courseId.contains(pTeachingCourseSegment.getBaseCourseId())) {
                                        courseId.add(pTeachingCourseSegment.getBaseCourseId());
                                    }
                                }
                            }


                            //获取当前培养方案未启用课程
                            List<ClassCourseClose> classCourseCloses = classCourseCloseListCourse.stream()
                                    .filter(p -> p.getGradeId().equals(taskToGrade.getGradeId())
                                            && p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId()))
                                    .collect(Collectors.toList());

                            List<PlanTeachingToStudent> collect10 = planTeachingToStudents.stream().filter(p -> p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId())).distinct().collect(Collectors.toList());

                            //当前培养方案应用几个班级
                            List<String> collect11 = collect10.stream().map(PlanTeachingToStudent::getClassId).distinct().collect(Collectors.toList());

                            Integer classNum = collect11.size();

                            //当前培养方案未启用课程存在几个班级
                            Map<Long, List<ClassCourseClose>> collect12 = classCourseCloses.stream().collect(Collectors.groupingBy(ClassCourseClose::getCourseId));


                            //如果培养方案应用班班级数量和未启用班级数量不一致，则显示启用，否则显示不启用
                            courseId.forEach(o -> {
                                if (ObjUtil.isNull(collect12.get(courseMap.get(o)))) {
                                    if (!baseCourse.contains(courseMap.get(o))) {
                                        baseCourse.add(courseMap.get(o));
                                    }
                                } else {
                                    List<ClassCourseClose> classCourseCloseList = collect12.get(courseMap.get(o));

                                    if (classCourseCloseList.size() != classNum) {
                                        if (!baseCourse.contains(courseMap.get(o))) {
                                            baseCourse.add(courseMap.get(o));
                                        }
                                    }
                                }
                            });



                            //环节同课程
                            Set<String> segmentId = new HashSet<>();
                            List<PlanTeachingCourseSegment> pTeachingCourseSegments1 = planTeachingCourseSegments.stream()
                                    .filter(p -> p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId())
                                            && p.getFlag() == 2).collect(Collectors.toList());

                            if (CollUtil.isNotEmpty(pTeachingCourseSegments)) {
                                for (PlanTeachingCourseSegment pTeachingCourseSegment : pTeachingCourseSegments1) {
                                    if (!segmentId.contains(pTeachingCourseSegment.getBaseCourseId())) {
                                        segmentId.add(pTeachingCourseSegment.getBaseCourseId());
                                    }
                                }
                            }

                            List<ClassCourseClose> classSegmentCloses = classCourseCloseListSegment.stream()
                                    .filter(p -> p.getGradeId().equals(taskToGrade.getGradeId())
                                            && p.getBaseTeachingPlanId().equals(planTeaching.getBaseTeachingPlanId()))
                                    .collect(Collectors.toList());

                            Map<Long, List<ClassCourseClose>> collect2 = classSegmentCloses.stream().collect(Collectors.groupingBy(ClassCourseClose::getCourseId));


                            segmentId.forEach(o -> {
                                if (ObjUtil.isNull(collect2.get(segmentMap.get(o)))) {
                                    if (!baseSegment.contains(segmentMap.get(o))) {
                                        baseSegment.add(segmentMap.get(o));
                                    }
                                } else {
                                    List<ClassCourseClose> classCourseCloseList = collect2.get(segmentMap.get(o));

                                    if (classCourseCloseList.size() != classNum) {
                                        if (!baseSegment.contains(segmentMap.get(o))) {
                                            baseSegment.add(segmentMap.get(o));
                                        }
                                    }
                                }
                            });


                        }

                        majorVo.setClasNum((long) classInfos2.size());
                        majorVo.setRoomNum((long) classInfos3.size());
                        majorVo.setCourseNum((long) baseCourse.size());
                        majorVo.setSegmentNum((long) baseSegment.size());
                        majorVos.add(majorVo);

                    }


                }
                gradeVo.setFacultyMajorInfoList(majorVos);

            }
            gradeVos.add(gradeVo);
        }


        //返回对应行政班信息
        PageInfo<GradeVo> gradePage = PagingUtil.getPages(currentPage, pageSize, gradeVos);

        List<GradeVo> list = gradePage.getList();
        List<GradeVo> collect = list.stream().sorted(Comparator.comparing(GradeVo::getGradeName)).collect(Collectors.toList());

        return ClassInfoByMajorResponse.builder()
                .facultyGradeInfoList(collect)
                .totalMajor(majorSet.size())
                .majors(new ArrayList<>(majorSet))
                .currentPage(gradePage.getCurrentPage())
                .pageSize(gradePage.getPageSize())
                .total(gradePage.getTotal())
                .build();
    }

    @Override
    public List<RuleTeachingClassVo> getRuleTeachingClass(Integer taskId, Long roomId, Long teacherId, Long classId, Long teachingClassId) {
        //根据固排类型 获取教学班
        List<RuleTeachingClassVo> teachingClassList = teachingClassService.getRuleTeachingClass(taskId, roomId, teacherId, classId, teachingClassId);
        //排除拆班
        if (teachingClassId == null) {
            teachingClassList = teachingClassList.stream().filter(o -> StrUtil.isEmpty(o.getUniqueShiftSign()))
                    .collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream().map(RuleTeachingClassVo::getTeachingClassId).distinct().collect(Collectors.toList());

            //获取教学班的骨牌规则
            List<RuleTeachingClassProhibit> classRule = ruleTeachingClassProhibitService.list(new LambdaQueryWrapper<RuleTeachingClassProhibit>()
                    .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                    .eq(RuleTeachingClassProhibit::getFlag, 1)
                    .eq(RuleTeachingClassProhibit::getDeleted, Deleted.NOT.getCode())
                    .in(RuleTeachingClassProhibit::getTeachingClassId, teachingClassIds)
                    .ne(RuleTeachingClassProhibit::getType, FixType.Course.getCode()));


            //前端没用过
            for (RuleTeachingClassVo teachingClass : teachingClassList) {
                teachingClass.setArranged((int) classRule.stream().filter(o -> o.getTeachingClassId().equals(teachingClass.getTeachingClassId())
                        && o.getHourType().equals(teachingClass.getHourType()) && o.getFlag() == 1).count());
                if (teachingClass.getWeekNum() < teachingClass.getConnectSection() * teachingClass.getConnectNumber()) {
                    teachingClass.setArrange(((teachingClass.getWeekNum() / teachingClass.getConnectSection()) * teachingClass.getConnectNumber()) - teachingClass.getArranged());
                } else {
                    teachingClass.setArrange(teachingClass.getWeekNum() - teachingClass.getArranged());
                }
                teachingClass.setProhibits(classRule.stream().filter(o -> o.getTeachingClassId().equals(teachingClass.getTeachingClassId())
                        && o.getHourType().equals(teachingClass.getHourType())).collect(Collectors.toList()));
            }

        }

        return teachingClassList;
    }

    @Override
    public Boolean checkTaskInfoName(String taskInfoName) {
        List<String> taskInfoNames = taskInfoMapper.getTaskNameList();

        if (taskInfoNames.contains(taskInfoName)) {
            return false;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> syncUpdatePeriodSchemes(Integer taskId, String schoolId, String term) {
        List<RuleWeekDay> ruleWeekDays = ruleWeekDayService.lambdaQuery()
                .eq(RuleWeekDay::getSchoolId, schoolId)
                .eq(RuleWeekDay::getTerm, term)
                .eq(RuleWeekDay::getDeleted, Deleted.NOT.getCode())
                .list();
        if (CollUtil.isEmpty(ruleWeekDays)
                || ruleWeekDays.stream()
                        .map(RuleWeekDay::getTaskId).distinct().count() != 1
                || !ruleWeekDays.get(0).getTaskId().equals(taskId)){
            return Result.ofSuccess();
        }

        Integer count = scheduleMapper.checkHasSchedule(taskId, schoolId, term, Deleted.NOT.getCode());
        if (count != null && count > 0) {
            return Result.ofSuccess();
        }

        List<PeriodScheme> periodSchemes = yunService.getPeriodScheme(taskId, schoolId, term);
        if (CollUtil.isEmpty(periodSchemes)) {
            return Result.ofSuccess();
        }


        List<String> periodSchemeIds = periodSchemes.stream().map(PeriodScheme::getBaseSchemeId).distinct().collect(Collectors.toList());
        Map<String,  List<PeriodScheme>> schemeMap = periodSchemes.stream().collect(Collectors.groupingBy(PeriodScheme::getBaseSchemeId));
        for (RuleWeekDay ruleWeekDay : ruleWeekDays) {
            String baseSchemeId = ruleWeekDay.getBaseSchemeId();
            if (!periodSchemeIds.contains(baseSchemeId)){
                String schemeId = periodSchemeIds.get(0);
                ruleWeekDay.setBaseSchemeId(schemeId);
                ruleWeekDay.setBaseSchemeName(schemeMap.get(schemeId).get(0).getBaseSchemeName());
            }
        }


        //删除多余的
        List<String> oldTimeCode = new ArrayList<>();
        List<String> nowTimeCode = new ArrayList<>();
        for (RuleWeekDay weekDay : ruleWeekDays) {
            String weekDayCode = weekDay.getWeekDayCode();
            List<PeriodScheme> schemeList = schemeMap.get(weekDay.getBaseSchemeId());
            schemeList.forEach(o -> nowTimeCode.add(weekDayCode + "0" + o.getPeriod()));
        }
        oldTimeCode.addAll(ruleClassProhibitService.lambdaQuery().eq(RuleClassProhibit::getTaskId,taskId)
                .list().stream().map(RuleClassProhibit::getTimeCode).distinct().collect(Collectors.toList()));
        oldTimeCode.addAll(ruleCourseProhibitService.lambdaQuery().eq(RuleCourseProhibit::getTaskId,taskId)
                .list().stream().map(RuleCourseProhibit::getTimeCode).distinct().collect(Collectors.toList()));
        oldTimeCode.addAll(ruleRoomProhibitService.lambdaQuery().eq(RuleRoomProhibit::getTaskId,taskId)
                .list().stream().map(RuleRoomProhibit::getTimeCode).distinct().collect(Collectors.toList()));
        oldTimeCode.addAll(ruleTeacherTimeService.lambdaQuery().eq(RuleTeacherTime::getTaskId,taskId)
                .list().stream().map(RuleTeacherTime::getTimeCode).distinct().collect(Collectors.toList()));
        oldTimeCode.addAll(ruleTeachingClassProhibitService.lambdaQuery().eq(RuleTeachingClassProhibit::getTaskId,taskId)
                .list().stream().map(RuleTeachingClassProhibit::getTimeCode).distinct().collect(Collectors.toList()));
        oldTimeCode.addAll(ruleTimeProhibitService.lambdaQuery().eq(RuleTimeProhibit::getTaskId,taskId)
                .list().stream().map(RuleTimeProhibit::getTimeCode).distinct().collect(Collectors.toList()));

        oldTimeCode.addAll(scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>().eq(Schedule::getTaskId,taskId))
                .stream().map(Schedule::getTimeCode).distinct()
                .filter(StrUtil::isNotEmpty)
                .collect(Collectors.toList()));
        oldTimeCode = oldTimeCode.stream().filter(StrUtil::isNotEmpty).collect(Collectors.toList());
        //计算少掉的课时
        List<String> removeTimeCodes = CollUtil.subtractToList(oldTimeCode, nowTimeCode);
        //如果少掉一些课时  删除该课时的规则和课表信息
        if (CollUtil.isNotEmpty(removeTimeCodes)) {
            List<Long> unSuitIds = ruleTeachingClassProhibitService.lambdaQuery()
                    .eq(RuleTeachingClassProhibit::getTaskId, taskId)
                    .eq(RuleTeachingClassProhibit::getFlag, 1)
                    .in(RuleTeachingClassProhibit::getTimeCode, removeTimeCodes)
                    .list().stream().map(RuleTeachingClassProhibit::getTeachingClassId)
                    .distinct().collect(Collectors.toList());

            //删除固排 禁排信息
            timeProhibitSuit(taskId, removeTimeCodes, -1);

            //删除课表  冲突  更新排课状态
//                removeAllSchedules(taskId);
            removeSchedules(taskId, removeTimeCodes);
            //如果是未满足规则的
            if (CollUtil.isNotEmpty(unSuitIds)) {
                //跟新排课状态
                unSuitIds.forEach(o -> arrangeCourseService.manualAdjustmentUpdate(schoolId, term, taskId, null, o));
            }
        }
        periodSchemeMapper.delete(new LambdaQueryWrapper<PeriodScheme>().eq(PeriodScheme::getTaskId,taskId));
        periodSchemeMapper.addBatch(periodSchemes);
        ruleWeekDayService.saveOrUpdateBatch(ruleWeekDays);

        return Result.ofSuccess();
    }

    @Override
    public void removeAllRule(List<Integer> taskIds) {
        ruleCourseProhibitService.lambdaUpdate().in(RuleCourseProhibit::getTaskId, taskIds).remove();
        ruleRoomProhibitService.lambdaUpdate().in(RuleRoomProhibit::getTaskId, taskIds).remove();
        ruleTeacherTimeService.lambdaUpdate().in(RuleTeacherTime::getTaskId, taskIds).remove();
//        ruleUsableMapper.delete(new QueryWrapper<RuleUsable>().in("task_id", taskIds));
//        ruleWeekDayService.lambdaUpdate().in(RuleWeekDay::getTaskId, taskIds).remove();

        ruleClassProhibitService.lambdaUpdate().in(RuleClassProhibit::getTaskId, taskIds).remove();
        ruleCourseService.lambdaUpdate().in(RuleCourse::getTaskId, taskIds).remove();
        ruleCourseProhibitMajorService.lambdaUpdate().in(RuleCourseProhibitMajor::getTaskId, taskIds).remove();
        ruleTeachingClassProhibitService.lambdaUpdate().in(RuleTeachingClassProhibit::getTaskId, taskIds).remove();

        arrangeProcessService.lambdaUpdate().in(ArrangeProcess::getTaskId, taskIds).remove();

        ruleTimeProhibitService.lambdaUpdate().in(RuleTimeProhibit::getTaskId, taskIds).remove();
        ruleTeacherSettingService.lambdaUpdate().in(RuleTeacherSetting::getTaskId, taskIds).remove();
    }
}


